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 類屬性 、實例屬性,可變數據結構作為類屬性需要註意的地方