MENU

Python类变量与成员变量相互影响的原因超详细解释

• March 19, 2018 • 编程语言

Python类变量与成员变量相互影响的原因超详细解释

今天看到了这样一篇文章:http://www.jb51.net/article/112525.htm

讲的是类变量和成员变量的影响原因,但原文并没有讲明详细原因,只是讲清楚了类变量与成员变量影响的结论,由于前几日看了《Python学习手册》这本书了解了一下Python的数据储存机制,然后自己想并且试验了一下,大致找到了原因,由于作者水平有限如原因有错请多原谅并指出,感激不尽。

先科普一下Python的数据储存机制,知道的就跳过往下看吧,Python的变量不用声明且可以随意赋值,因为Python的变量其实是类似C语言中指针的包装,例如python中

<center>a=3</center>


所以在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指向内存空间的值并没有改变。

Archives QR Code
QR Code for this page
Tipping QR Code