Python中类内定义类的变量中的bug


2018-12-5

今天看到有人在类内的初始化函数__init_(self,…)之前定义类的变量:

python内部类互相引用 python 内部类调用外部类变量_定义类


不是很明白为什么要在__init__()之外先定义一个变量x。于是就自己做实验测试了一下,之前定义的x=1和__init__()函数内的self.x=_x有何区别。

如下方式定义类A,

python内部类互相引用 python 内部类调用外部类变量_内存地址_02


1. 内外变量虽然有相同的变量名,但分配不同地址

定义了A的对象a=A(1)

python内部类互相引用 python 内部类调用外部类变量_python_03


可以看到a.x是经过__init__()函数初始化过的对象的变量,而A.x是类A本身的变量,与对象a并无关系。

id()函数查看了变量的地址,a.xA.x的地址并不相同。2. 当内外变量值一致时,可能会是相同地址

当我再次定义一个A的对象b,b=A(2),查看b.x的地址,发现id(b.x)=id(A.x)

python内部类互相引用 python 内部类调用外部类变量_内存地址_04


如上面所显示的,b.x和A.x的地址竟然是一样的。

于是我又改变了b.x的值,

python内部类互相引用 python 内部类调用外部类变量_内存地址_05


然后我又发现当我改变b.x的值为5,使其不等于A.x时,b.x的地址竟然又改变。

我就很不明白这是怎么一回事,后来在网上百度。看到其他网友关于id函数的解释:

python内部类互相引用 python 内部类调用外部类变量_定义类_06


引用链接:

也就是说,我们发现当a.x=A.x=2时,二者的内存是一样的,和类中变量的定义是无关的。只不过是python对于小型整数分配内存中的一种资源的共享。

然后,我就用大型的整数又做了一次实验:

python内部类互相引用 python 内部类调用外部类变量_内存地址_07


a.x=b.x=A.x=1000,用id函数再次看三个变量的内存就发现它们是相互无关的。

就是这样了,以后还是可以放心大胆的在类内为类本身定义变量了。


/*----------更新 2019-4-21-----------*/
这里之所以小整数时内存会一样其实和__init__函数无关。这里涉及到了python的内存管理机制。
在python中所有的东西都是对象,整数也是。
比如a = 1,在python看来,a是变量,而1是对象。前面的语句就是将a这个变量指向了对象1。python有个特别的机制,它会在解释器启动的时候事先分配好一些缓冲区,这些缓冲区部分是固定好取值,例如整数[-5, 256]的内存地址是固定的(一旦启动python程序,内存就分配好了,但下次启动分配的地址可能就变了)。所以a = 1b = 1两个语句都是将a,b指向了整数1所在的内存地址,而python程序已经为1分配好了内存地址,所以a和b指向的地址是相同的。但如果a = 267, b = 267,a和b的内存地址就不是一样的。
另外,除了整数,python也为字符串设立了静态缓冲区,对于只包含字母和数字的字符串,地址也是固定不变的。