对象
先来看一个例子,解释一下python的对象机制
a = 1
print(id(a))
a = 2
print(id(a))
不了解对象的同学可能会觉得,“a=1"的意思是将1赋值给变量a
但是不然,该语句的意思其实是:将变量a指向一个对象,该对象的值为1。
也就是说,a只是充当对象的一个引用。
再看语句"a=2”,同样地,该语句的意思是:将变量a指向另一个对象,该对象的值为2。并不是把2赋值给a的意思
输出如下,可以看到,a指向的变量的地址改变了。
140736831005072
140736831005104
可能你还是不太明白,那么再举一个列表的栗子
a = [1, 2]
b = a
a.append(1)
print(a, b) # [1, 2, 1][1, 2, 1]
a = [1, 2, 3, 4]
print(a, b) # [1, 2, 3, 4] [1, 2, 1]
我们来逐行解释代码
- 将变量a指向了一个列表对象,值为[1, 2]
- 将变量b指向了a指向的对象,也就是说现在a, b变量指向同一个对象
- 修改a指向的对象的值(而不是修改a)
- 显然,因为a,b指向的对象被修改了(第三步),所以a,b结果相同
- 将a指向了另一个对象[1, 2, 3, 4](对象[1, 2]并未被修改)
- 此时b仍指向对象[1, 2, 3]([1, 2]在第三步被修改后变成[1, 2, 3])
因此,我们可以说。
- 修改一个变量,其实是修改该变量指向的对象
- 变量其实是对象的一个引用
可变对象与不可变对象
可变对象:对象存放在地址中的值可以被改变
不可变对象:对象存放在地址中的值不可以被改变
- 典型的可变对象包括list,dict等
- 典型的不可变对象包括int, float, tuple等
可能你会有疑问,int型变量的值是可以改变的啊?我想让它等于多少就等于多少。
但请注意,这里的可变不可变指的是对象,当你改变int型变量的值时,其实是改变了该变量指向的对象。
对于两者的区别,用大白话说就是:可变对象可以在对象的地址不改变的情况下,改变对象的值(如列表中的append()方法)。而不可变对象则不能,如果想修改不可变对象的值,只能选择新建另一个对象。
a+=b VS a=a+b
可能你会问,这两个式子有什么区别?最后a的结果不都是a+b嘛?
是的,在算法层面两个式子几乎等价,但在内部机理上有所不同。
首先我们观察,当变量a指向不可变对象时:
a = 1
print(id(a)) # 140736831005072
a += 1
print(id(a)) # 140736831005104
a = a+1
print(id(a)) # 140736831005136
可以看到,3个id(a)均不相同,也就是说,因为a指向了不可变对象,所以+=和=+都会使a指向一个新的对象
接下来,我们看当变量a指向可变对象时:
a = [1]
print(id(a)) # 2692742533576
a += [1]
print(id(a)) # 2692742533576
a = a+[1]
print(id(a)) # 2692773707144
观察到了什么?在a+=[1]后,a指向的对象的地址没有变化。而在=+操作后,却变化了。
也就是说:
- +=操作其实是对原对象[1]的改变(原地改变)
- 而=+操作是创造了一个新的[1, 1]对象,并使a指向该对象
关于更深层次的原因,请参阅参考资料1
参考资料
- https://www.jianshu.com/p/cada506e19d9
- https://blog.csdn.net/rookinzhang/article/details/80259857