python实例属性与类属性_Python中的类属性和实例属性引发的一个坑-续
上篇文章Python 中的類屬性和實例屬性,我們探討了類屬性和實例屬性引發的一個小坑。總結了類屬性和實例屬性的區別如下:類屬性可以被類和實例調用,實例屬性只能被實例調用
類屬性不會隨著實例的調用而改變
類屬性的有效作用域只有類,實例屬性的有效作用域只有本實例(有效作用域并非官方描述,而是我做的一個類比,大家可與作用域類別)。
其實第二點可以忽略,第三點已經涵蓋了。我把文章發給了小伙伴們品讀,有小伙伴針對第二三條提出了不同的看法。看如下例子:
class Persion(object):
count = 0
info = {
'name': '小明'
}
info_list = []
def __init__(self):
self.name = '人'
if __name__ == '__main__':
p = Persion()
p.count = 5
print(p.count) # 5
print(Persion.count) # 0
p.count += 5
print(p.count) # 10
print(Persion.count) # 0
p.info['name'] = '小紅'
print(p.info) # {'name': '小紅'}
print(Persion.info) # {'name': '小紅'}
p2 = Persion()
p2.info = {'name': 'Tom'}
print(p2.info) # {'name': 'Tom'}
print(Persion.info) # {'name': '小紅'}
實例中,info 的值被修改了,那么是否可以說「實例可以修改類屬性」了呢?我們來繼續分析,來看 count 和 info 區別,不難想到它們一個是「不可變變量(immutable type)」,一個是「可變變量(mutable type)」,這兩種變量類型的區別在于內存的使用。
Python 變量中實際上保存的是內存中值的引用,「不可變變量」修改時,是改變了引用,「可變變量」修改時,是改變了內存塊中的值。如下:不可變變量
i = 20
j = 20
print(id(i)) # 4299177184
print(id(j)) # 4299177184 不同變量引用了同一個值
i +=1
print(id(i)) # 4340788480 值變了,變量的引用地址也變了可變變量
d1 = [1, 2, 3]
d2 = [1, 2, 3]
print(id(d1)) # 4514412936
print(id(d2)) # 4511850248 # 相同值,變量的引用地址不同
d1.append(4)
print(id(d1)) # 4514412936 # 值變了,變量的引用地址沒變
說回我們討論的問題,當修改 info 的name key 所對應的值時,實際上是修改了內存塊中的值,因為實例p和類Person的 info 屬性都是指向了統一內存地址,所以類Person的 info 屬性的值也變了。而當我們直接給實例p的 info 屬性賦值時,它引用的是另一個內存地址的值,雖然值和類Person的 info 相同,但是引用不同,所以當p的屬性修改時,Person的 info 屬性沒有變化的。
那我們來總結一下:當類的屬性為不可變變量時,實例屬性是對類屬性值的引用,修改實例屬性僅僅是修改了引用,不會修改原來的值,即不會修改類屬性。
當類的屬性為可變變量時,分下面兩種情況:當直接修改實例屬性時,因為是可變變量,即把內存中的值修改了,所以類屬性的值也修改了。
當重新賦值實例屬性時,因為和類屬性的引用不同,即使值改變了,也不會影響類屬性的值。
那么上篇中結論有些不太嚴謹,需要針對「可變變量」和「不可變變量」做些區分,這里有些類似函數傳參時的作用域的關系。大家在實際應用中,一定要注意「可變變量」和「不可變變量」的區別。
更多「可變變量」和「不可變變量」資料可參閱:How do I pass a variable by reference?[1]
Facts and Myths about Python names and values[2]
參考資料
[2] Facts and Myths about Python names and values:
總結
以上是生活随笔為你收集整理的python实例属性与类属性_Python中的类属性和实例属性引发的一个坑-续的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python字典的用法_Python字典
- 下一篇: python中var是什么_这些Pyth