在Python中經常會混淆類屬性和實例屬性的概念,今天專門記錄一下個人理解以免日后忘記。
看下面的例子:
class Tencent(): i = 10 # 此處i為類屬性 def __init__(self,name): self.name = name # 此處name為實例屬性 def function(self): print(self.name) a = Tencent(100) #實例化 print(a.i) print(a.name) print(Tencent.i)
運行當然是沒有問題的,輸出結果為:
10 100 10
但是當我們加入這樣一段代碼:
print(Tencent.name)
運行后會報錯,這是因為不能通過類名+屬性名的方式去調用實例屬性,當類實例化后,只能通過類名去調用方法中的屬性。
下面進行這樣的操作:
Tencent.i += 1 print(a.i)print(Tencent.i)
輸出結果為:
11 11
然后再進行:
a.i + = 1 print(a.i) print(Tencent.i)
輸出結果則為:
11 10
Why?同樣是對類屬性的修改,為什么用不通的調用方式修改后輸出的值卻不一樣呢?
我自己的解釋如下:
當我們使用實例名+屬性名,即a.i的方式修改屬性i的值時:相當於新建了一個i的副本,+1這個操作實際上是進行在這個i的副本上的,而當我們用類名+屬性名的方式調用i時,輸出的其實是原封未動的類屬性i
驗證如下:
print(id(a.i)
print(Tencent.i)
a.i += 1 print(a.i,end=" "),print(id(a.i)) #輸出修改后a.i的內存地址 print(Tencent.i,end=" "),print(id(Tencent.i)) #輸出修改后Tencent.i的內存地址
輸出結果為:
140712785339504
140712785339504
11 140712785339536
10 140712785339504
結果顯示,修改前后,類屬性i的內存地址其實是沒有變的,通過實例調用修改i其實只是修改了副本。
同理,假如我們直接通過類名的調用方式來修改i,結果為:
print(id(a.i)) print(id(Tencent.i)) Tencent.i += 1 print(a.i,end=" "),print(id(a.i)) print(Tencent.i,end=" "),print(id(Tencent.i)) 140712785339504 140712785339504 11 140712785339536 11 140712785339536
可以看到,如果我們直接使用類名+屬性名的方式修改i,那么在修改后i的值確確實實的是變了。
總的來說,類和實例對於屬性的修改權限其實就是作用域的問題,類有權限修改屬性,而實例沒有,於是,實例就在自己的內存范圍內創建一個實例名+屬性名的副本,調用的時候就是用的這個。
