我正在尝试在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()
时,为什么不增加“静态”变量i
?
答案 0 :(得分:8)
当您分配到self.i
时,您正在创建名为i
的新实例变量:
>>> print id(A.i), id(a.i)
9437588 9437576
以下内容将更改A.i
而不是重新绑定a.i
:
A.i = A.i + 1
或者更短:
A.i += 1
答案 1 :(得分:2)
以下代码准确显示了发生的情况:
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 mapping from names to objects。
在创建了课程A
及其实例a
之后,只有A
具有属性i
,
a
没有。{
事实上,此时a
的命名空间是无效的,当解释器遇到a.i
时,它会这样做:
一个类实例有一个名称实现为字典的名称空间 搜索属性引用的第一个位置。当一个 在那里找不到属性,并且实例的类有一个 通过该名称的属性,搜索继续该类 属性。见3 Data model 3.2 The standard type hierarchy
中
在Python语言参考
也就是说,由于i
不是a
实例的属性,解释器会在A
的命名空间中搜索:在那里找到属性i
,它会将此属性作为a.i
现在,当执行a.add_i()
时,指令self.i = self.i + 1
的处理方式如下:
首先搜索self.i
:由于i
不是self
的属性(即a
),因此返回的对象位于事实A.i
。
其次,self.i + 1
然后创建一个新对象,其值为A.i
的递增值。但是现在这个对象与名称A.i
的对象不同:它具有不同的身份,也就是说在内存中有不同的本地化。
第三,有一个分配:self.i = .....
这意味着名称i
是在self
(名称为a
)的名称空间中创建的,并且绑定到刚刚创建的对象,其值增加。
因此,在add_i()
函数的开头和结尾之间,self.i
的含义发生了变化。
因此,a.i
指令后a.add_i()
的含义与之前的含义不再相同。
深入理解Python流程需要考虑标识符(名称)和对象在命名空间中播放的游戏,除此之外别无他法。
答案 2 :(得分:1)
因为您在类的实例上调用该方法,该实例具有自己的i
副本。此代码可以执行您希望它执行的操作。
class A(object):
i = 0
def add_i(self):
self.__class__.i += 1
>> a = A()
>> a.add_i()
>> A.i
1
答案 3 :(得分:1)
存在变量i
的副本。当您致电a.add_i()
时,a.i
会增加,而A.i
会变为相同。
#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()
答案 4 :(得分:0)
因为a.add_i()
不是静态方法,它只能增加静态变量
答案 5 :(得分:0)
为了更改类级变量,您可以定义类级方法
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']