2017-02-03 35 views
2

你会如何提出这个有趣的(至少对我来说)例子。与自己调用类变量

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修饰符修饰方法。

这是一种非法使用该语言吗?我的意思是最好不要做,以避免在后期阶段引入错误。

回答

5

正在发生的事情是,self.a是指在不同的时间的事情。

当没有实例变量存在名称时,Python将查找该类的值。因此,self.a的检索值将是类变量。

但当通过self设置属性,Python会始终设置一个实例变量。所以现在self.a是一个新的实例变量,它的值等于类变量+1。该属性给类属性加上阴影,你不能再通过self访问类属性,而只能通过类访问。

(一个小小的点,其中有无关的问题:你永远不应该直接访问而不是调用something2.__str__()的双下划线方法,调用str(something2)等)

0

由丹尼尔·罗斯曼回答清楚地解释了问题。这里有一些额外的观点,并希望它有帮助。 您可以使用type(self).a而不是self.a.也期待在讨论 Python: self vs type(self) and the proper use of class variablesPython: 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()