[英]Changing static variable from instance method in Python
我試圖在python中更改靜態變量
>>> class A():
... i = 0
... def add_i(self):
... self.i = self.i + 1
...
>>> A.i
0
>>> a = A()
>>> a.add_i()
>>> A.i
0
>>> a.i
1
當我調用a.add_i()
,為什么它不會遞增'static'變量i
?
當您分配給self.i
,您正在創建一個名為i
的新實例變量:
>>> print id(A.i), id(a.i)
9437588 9437576
以下將改變Ai
而不是重新綁定ai
:
A.i = A.i + 1
或者,更短:
A.i += 1
以下代碼准確顯示了發生的情況:
class A():
i = 0
def add_i(self):
print '\n-----In add_i function-----'
print 'BEFORE: a.__dict__ :',a.__dict__
print 'BEFORE: id(self) : %d\n' % id(self.i)
self.i = self.i + 1
print 'self.i = self.i + 1 done\n'
print 'AFTER: a.__dict__ :',a.__dict__
print 'AFTER: id(self) : %d' % id(self.i)
print '-----end of add_i function-----\n'
a = A()
print '\nA.i ==',A.i
print 'id(A.i) ==',id(A.i)
print 'A.__dict__.keys() :',A.__dict__.keys()
print '\na.i ==',a.i
print 'id(a.i) ==',id(a.i)
print 'a.__dict__.keys() :',a.__dict__.keys()
a.add_i()
print '\nA.i ==',A.i
print 'id(A.i) ==',id(A.i)
print 'A.__dict__.keys() :',A.__dict__.keys()
print '\na.i ==',a.i
print 'id(a.i) ==',id(a.i)
print 'a.__dict__.keys() :',a.__dict__.keys()
結果
A.i == 0
id(A.i) == 10021948
A.__dict__.keys() : ['i', 'add_i', '__module__', '__doc__']
a.i == 0
id(a.i) == 10021948
a.__dict__.keys() : []
-----In add_i function-----
BEFORE: a.__dict__ : {}
BEFORE: id(self) : 10021948
self.i = self.i + 1 done
AFTER: a.__dict__ : {'i': 1}
AFTER: id(self) : 10021936
-----end of add_i function-----
A.i == 0
id(A.i) == 10021948
A.__dict__.keys() : ['i', 'add_i', '__module__', '__doc__']
a.i == 1
id(a.i) == 10021936
a.__dict__.keys() : ['i']
對象的__dict__
暴露了對象的名稱空間,也就是說從名稱到保存其屬性的對象的映射 。
在創建了A
類及其實例a
,只有A
具有屬性i
,
a
沒有。
其實在這一刻,的命名空間a
是無效的,而當遇到intepreter ai
它是:
類實例具有作為字典實現的名稱空間,該字典是搜索屬性引用的第一個位置。 當在那里找不到屬性,並且實例的類具有該名稱的屬性時,搜索繼續使用類屬性。 參見3數據模型3.2標准類型層次結構
在Python語言參考中
也就是說,因為i
不是a
實例的屬性,解釋器去搜索A
的命名空間:它找到一個屬性i
並且它返回該屬性作為ai
調用的結果
。
現在,當執行a.add_i()
時,指令self.i = self.i + 1
的處理方式如下:
首先,搜索self.i
:因為i
不是self
(屬於a
)的屬性,所以返回的對象實際上是Ai
。
其次, self.i + 1
然后創建一個新對象,其值是Ai
的遞增值。 但是現在這個對象與名字Ai
的對象不同:它具有不同的身份,也就是說在內存中有不同的本地化。
第三,有一個分配: self.i = .....
這意味着名稱i
是在self
(即a
)的命名空間中創建的,並且綁定到剛剛創建的具有遞增值的對象。
所以在add_i()
函數的開頭和它的結尾之間, self.i
的含義已經改變了。
因此,指令a.add_i()
之后的ai
的含義與之前不同。
。
深入理解Python進程需要考慮標識符 (名稱)和對象在命名空間中播放的游戲,除此之外別無他法。
因為您正在類的實例上調用該方法,該實例具有它自己的i
副本。 此代碼可以執行您希望它執行的操作。
class A(object):
i = 0
def add_i(self):
self.__class__.i += 1
>> a = A()
>> a.add_i()
>> A.i
1
存在變量i
副本。 當你調用a.add_i()
, ai
增加,而Ai
會變為相同。
#a.i = 1, A.i = 1
a.add_i()
#a.i = 2, A.i = 2
想想如果你有什么會發生什么
a = A()
b = A()
a.add_i()
print A.i()
因為a.add_i()
不是靜態方法,它只能增加靜態變量
要更改類級變量,可以定義類級方法
In [15]: class A():
....: i = 0
....: @classmethod
....: def incr(cls):
....: cls.i += 1
....:
In [16]:
In [16]: A.incr()
In [17]: A.i
Out[17]: 1
In [18]: A().incr()
In [19]: A.i
Out[19]: 2
編輯:
或者在方法中引用類(而不是實例)
def incr(self):
A.i += 1
如果類級屬性是可變的,並且您想要更改它(而不是賦值),例如對於列表,您可以以任何方式進行
In [29]: class Class4Test(object):
mylist = []
@classmethod
def add2list_class(cls, val):
cls.mylist.append(val)
def add2list_by_class(self, val):
Class4Test.mylist.append(val)
def add2list_by_inst(self,val):
self.mylist.append(val)
....:
In [30]: obj = Class4Test()
In [31]: obj.add2list_by_inst('val1')
In [32]: obj.add2list_by_class('val2')
In [33]: Class4Test.add2list_class('val3')
In [34]: obj.add2list_class('val4')
In [35]: Class4Test.mylist
Out[35]: ['val1', 'val2', 'val3', 'val4']
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.