你怎么想出这个有趣的(至少对我而言)的例子。
import numpy as np
class Something(object):
a = np.random.randint(low=0, high=10)
def do(self):
self.a += 1
print(self.a)
if __name__ == '__main__':
something = Something()
print(something.__str__())
something.do()
something2 = Something()
print(something2.__str__())
something2.do()
something3 = Something()
print(something3.__str__())
something3.do()
以上内容在控制台中打印以下内容:
$ python test.py
<__main__.Something object at 0x7f03a80e0518>
1
<__main__.Something object at 0x7f03a80cfcc0>
1
<__main__.Something object at 0x7f03a80cfcf8>
1
我有点困惑,因为我(错误地)认为a
的价值会增加。
如果我使用@classmethod
装饰器,我就能获得我期望的行为。
import numpy as np
class Something(object):
a = np.random.randint(low=0, high=10)
@classmethod
def do(cls):
cls.a += 1
print(cls.a)
if __name__ == '__main__':
something = Something()
print(something.__str__())
something.do()
something2 = Something()
print(something2.__str__())
something2.do()
something3 = Something()
print(something3.__str__())
something3.do()
这会在控制台中正确打印以下内容。
python test.py
<__main__.Something object at 0x7faac77becc0>
3
<__main__.Something object at 0x7faac77becf8>
4
<__main__.Something object at 0x7faac77c3978>
5
现在,我想知道第一个例子,当我打电话给self.a
时,我正在访问什么?它不是一个类变量,因为我似乎无法改变它的值。它也不是一个实例变量,因为它似乎在同一个类的不同对象之间共享。你怎么称呼它?
这是一个我以错误的方式使用的类变量吗?我知道cls
名称是一个约定,所以也许我真正访问一个类变量,但我无法更改其值,因为我没有使用@classmethod
装饰器修饰该方法
这是一种非法使用的语言吗?我的意思是,最好的做法是不要做以避免在后期引入错误?
答案 0 :(得分:5)
正在发生的事情是UPDATE users set name = 'John' where id = 1
在不同时间引用两个事物。
如果名称不存在实例变量,Python将查找该类的值。因此,为self.a
检索的值将是类变量。
但是当通过self.a
设置属性时,Python将始终设置实例变量。所以现在self
是一个新的实例变量,其值等于类变量+ 1.这个属性隐藏了class属性,你不能再通过self.a
访问它,只能通过类。
(一个小问题,与问题无关:你永远不应该直接访问双下划线方法。而不是调用self
,请致电something2.__str__()
等。)
答案 1 :(得分:0)
Daniel Roseman的回答清楚地解释了这个问题。这里有一些额外的观点,希望它有所帮助。 您可以使用type(self).a而不是self.a.另请参阅讨论 Python: self vs type(self) and the proper use of class variables和 Python: self.__class__ vs. type(self)
import numpy as np
class Something(object):
a = np.random.randint(low=0, high=10)
def do(self):
type(self).a += 1
print(type(self).a)
if __name__ == '__main__':
something = Something()
print(str(something ))
something.do()
something2 = Something()
print(str(something2))
something2.do()
something3 = Something()
print(str(something3))
something3.do()