Python 的数据类型分为可变类型不可变类型 , 可变类型的对象的值是可以被修改的 , 称为可变对象 , 而不可变类型的对象的值是不可修改的 , 称为不可变对象。数值类型、str类型、tuple类型都是不可变类型 , 而list 类型、set 类型、dict 类型等都是可变类型。例如 , 一个list 对象的值是可以修改的 , 即可以对其中的元素进行修改、删除、添加等操作。例如:

>>> a = [1,2,3]
>>> a[0] = 4
>>> print(a)
[4, 2, 3]

可以看到 , 变量a引用的list对象的第1个元素被修改了。因为tuple对象是不可修改的 , 下面代码将产生错误:

t = (1,2,3) 
t[0] = 4 

产生了类型错误"TypeError: 'tuple' object does not support item assignment"。

但下面代码不会有任何错误:

>>> t= (1,2,3)
>>> print(t)
(1, 2, 3)
>>> t =(4,5,6)
>>> print(t)
(4, 5, 6)

上述代码中的变量名分别指向了不同的tuple对象 , 而它们指向的tuple对象本身并没有被修改。 前面讲过, 变量是对象的引用, 也就是说 , 变量仅是对象的别名 , 而不是对象本身。当变量t 引用不可修改的tuple对象(1,2,3)时 , 这个tuple对象不可修改 , 但可以对变量名t重新赋值 , 如"t= (4,5,6)"使变量t又引用了这个新的tuple对象。

可以通过下面代码进一步理解上述内容:

>>> x = "hello"
>>> y = x
>>> print(x is y)          #x,y指向同一个不可修改对象hello
True
>>> print(id(x),id(y))
2229121649584 2229121649584
>>> x = "world"            #x引用了新对象world , 而并未修改对象hello
>>> print(y)               #y仍然引用的是对象hello
hello
>>> print(x)               #x引用的是新对象world
world
>>> print(id(x),id(y))
2229121649904 2229121649584

可以看到 , 变量x前后指向的是不同的对象 , 而并未修改变量x指向的对象。 同样 , 执行复合赋值语句 , 如"x+=1"等 , 并不修改x指向的对象 , 而是让x指向新创建的对象。例如:

>>> x = 2
>>> y = x        #y和x指向了同1个对象2
>>> print(id(x),"\t", id(y))
2229116207376    2229116207376
>>> x+=1        #x+1等价于x = x+1。因为x指向的int对象是不可修改的(immutable)
>>>             #用x+1的结果给x赋值 , 就是让x变量名指向这个新的结果值对象
>>> print(x)
3
>>> print(y)
2
>>> print(id(x),"\t",id(y))
2229116207408    2229116207376

其中 , "x+=1"使得x引用了新对象 , 而并没有修改原来x引用的不可变对象"2" 。

如果1个变量指向的是1个可修改的(mutable)对象 , 那么可以通过这个变量修改它指向的对象 , 而这个时候并不会创建新对象。例如:

>>> a= [2,3]
>>> b = a        #b和a都是list对象[2,3]的引用
>>> a[0] = 4     #修改a指向的list对象的第1个元素
>>> print(a)
[4, 3]
>>> print(b)
[4, 3]
>>> print(id(a))
2229121622976
>>> print(id(b))
2229121622976
>>> b[1] = 7
>>> print(a)
[4, 7]
>>> print(b)
[4, 7]

可以看出 , 上述代码修改ab指向的list对象的元素 , 并没有修改ab本身。因此 , ab始终指向的是同1个对象 , 无论变量指向的是1个可修改的对象还是不可修改的对象 , 给这个变量赋值都会使这个变量引用其他的对象。例如:

>>> a = [2,3]
>>> print(id(a))
2229121112064
>>> a = [4,5]
>>> print(id(a))
2229121622528

再看下面的代码:

>>> a= (1, [2,3], 4)
>>> b = a
>>> #a[1] = 20       #错:元祖a的元素是不可修改的
>>> print(a[1])
[2, 3]
>>> print(id(a[1]))
2229121112064
>>> a[1][0]=20    #a[1]元素是一个list对象 , 是可修改的
>>> print(a[1])
[20, 3]
>>> print(id(a[1]))
2229121112064

因为元组a是不可修改的 , 即不可以修改其内容如元素a[1]的值 , 即"a[1]=20"将出错 , 但可 以修改a[1]引用的那个可变list对象[2,3]。因此 , "a[1][0]=20"是可以修改的。通过输出a[1]id 值 , 可以发现 , 作为元素a的元素 , a[1]的值没有改变 , 仍然引用的是原先的list对象 , 但其引用的 list对象内容发生了变化(通过打印a[1]可知道这一点)。以上修改a[1]引用的list对象的。


熊熊