python 类属性 实例属性,可变数据结构作为类属性需要注意的地方

Posted jason89

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 类属性 实例属性,可变数据结构作为类属性需要注意的地方相关的知识,希望对你有一定的参考价值。

有一个大笨猪,按java写观察者模式,java写得是直接在类名下声明一个实例属性(不加static的),他直接翻译成python后,也是直接写在类名下面,这就是大坑了。

java里面在类名下面声明的带static为类属性,不带static为实例属性,python如果直接写在类名下面的属性,一律都是类属性,实例属性一般都是在init里面写的,带self字眼的变量。

 

 

技术分享图片

 

技术分享图片
#coding:utf-8

class A():
    x_list = []

a1 = A()
a1.x_list.append(1)
a2 = A()
print(‘第一个结果 -->‘,a2.x_list)



class B():
    x = 0

b1 = B()
b1.x =1
b2 = B()
print(‘第二个结果‘,b2.x)



class C():
    x = 0

c1 = C()
C.x =1
c2 = C()
print(‘第二个结果‘,c2.x)
技术分享图片

运行结果是这样的。

技术分享图片

对比 A B C三个类可以发现,类属性自己一份,实例属性默认等于类属性。

比如B类,实例b1的x默认等于0,当赋值为1时候,b1的x就等于1了,此时B类的属性x仍然等于0,b2实例的属性x也是等于0。

c类,直接改变C类的x属性,则C的x变为1了,如果实例化一个新的c2,默认就等于1了。

 

B和C的这种操作是很多案例上都有的,烂大街了,一定需要查看常见容易错误的案例。

 

最主要还是A类,A类的x_list是一个列表,列表是可变数据结构,用可变次数据结构作为类属性,就要很小心了,即使是用实例a1操作x_list,仍然会影响A的属性x_list和a2的属性x_list。当可变元素作为类属性时候,操作 a.x_list和A.x_list是等效的,都是互相影响的。

不可变数据结构例子:

a_str = ‘hello’

b_str = a_str

b_str = a_str + ‘world‘

最终a的值是hello ,b的值是hello world。

 

可变的数据结构例子:

a_list = [‘hello‘]

b_list = a_list

b_list + = [‘world‘]

最终a_list和b_list的值都是[‘hello‘, ‘world‘]

 

 

回到题目就是,在观察者模式中,如果把订阅者添加到类属性x_lsit列表,那么所有的发布者都共享了所有的订阅者。

比如小明、小军订阅了苍老师,小红 小黄订阅了波老师,但苍老师更新电影时候,由于共享了订阅者,导致小红和小黄也收到新片通知了,这显然是个错误。

 

所以苍老师和波老师的x_list必须是独立的,需要写在__init__里面,写成self.x_list,这样苍老师和波老师的x_list就都是独立的了,添加订阅者到苍老师的列表,波老师的列表不会跟着变化。

以上是关于python 类属性 实例属性,可变数据结构作为类属性需要注意的地方的主要内容,如果未能解决你的问题,请参考以下文章

python-类

谨慎修改Python的类属性

使用类实例作为类属性、描述符和属性

python基础类的定义与使用

Python类设置器 - 每次创建新实例时都会重新分配类属性吗?

不可变类