Python类变量与成员变量相互影响的原因超详细解释
今天看到了这样一篇文章:http://www.jb51.net/article/112525.htm
讲的是类变量和成员变量的影响原因,但原文并没有讲明详细原因,只是讲清楚了类变量与成员变量影响的结论,由于前几日看了《Python学习手册》这本书了解了一下Python的数据储存机制,然后自己想并且试验了一下,大致找到了原因,由于作者水平有限如原因有错请多原谅并指出,感激不尽。
先科普一下Python的数据储存机制,知道的就跳过往下看吧,Python的变量不用声明且可以随意赋值,因为Python的变量其实是类似C语言中指针的包装,例如python中
a=3
-------------------------------------------------------------------------------------------------------------------------------------------------
所以在python中变量皆为指针。那么,看看原文章中的例子
class A:
x = []
y = 0
def __init__(self):
pass
def add(self):
self.x.append('1')
self.y+=1
a=A()
print a.x,a.y
print A.x,A.y
a.add()
print a.x,a.y
print A.x,A.y
b=A()
print b.x,b.y
print A.x,A.y
输出结果为
[]
0
[]
0
[
'1'
]
1
[
'1'
]
0
[
'1'
]
0
[
'1'
]
0
-------------------------------------------------------------------------------------------------------------------------------------------------
先来从头到尾分析一遍:因为首先生成a这个对象并没有实例变量(__init__没有参数),所以虽然a实例和A类为两个不同内存地址,但是a.x和A.x却都是引用类A变量x的内存地址(类创建的时候一块内存地址出现了[]这个值,由于后续生成实例并没有赋值操作,所以整个内存中有且仅有一个[]值,又因为变量为指针,所以这个两个变量同时指向[]的内存地址)
所以当a调用a.add方法时,self传的又是自身,相当于执行了a.x.append('1'),而a.x与A.x指向的内存相同,由于a.append函数并不改变变量a指向的内存地址,而是改变内存地址中的值(相当于在a所指的内存地址中的原值进行操作即对[]进行操作)
a=[]
print(id(a))
a.append('a')
print(id(a))
输出结果为两个相同的值,即append函数是对原值进行了操作。所以A类对象本身值被改变,以至于接下来生成的b实例的b.x值也被改变,那么为什么A.y这个值却没有改变呢?
-------------------------------------------------------------------------------------------------------------------------------------------------
下面分析y这个类变量,给你们下面这段代码你们应该就懂了
i = 1
print(id(i))
i +=1
print(id(i))
输出结果是两个不同的值 原理是假设1这个值被存放在0xF0这个内存空间,进行i+=1的时候,1+1=2,2这个值生成并被放在假设0xFF这个地址内,然后i从指向0xF0转为指向0xFF,而不是2这个值覆盖原地址。
根据这个结论来讨论我们的问题a.add()的函数进行了self.y+=1的操作,虽然self.y 和 a.y 和 A.y为同一个内存地址,但是self.y+=1却只是改变了self.y的指向,代码执行后self.y指向了另一块内存地址而A.y指向的内存地址没变,相当于创建了一个副本,所以在接下来生成b实例的时候b.y的值还是0,因为类变量y指向内存空间的值并没有改变。