用self调用类变量

Gia*_*uca 2 python instance-variables class-variables python-3.x

你怎么想出这个有趣的(至少对我而言)的例子.

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()
Run Code Online (Sandbox Code Playgroud)

以上内容在控制台中打印以下内容:

$ python test.py
<__main__.Something object at 0x7f03a80e0518>
1
<__main__.Something object at 0x7f03a80cfcc0>
1
<__main__.Something object at 0x7f03a80cfcf8>
1
Run Code Online (Sandbox Code Playgroud)

我有点困惑,因为我(错误地)认为价值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()
Run Code Online (Sandbox Code Playgroud)

这会在控制台中正确打印以下内容.

python test.py
<__main__.Something object at 0x7faac77becc0>
3
<__main__.Something object at 0x7faac77becf8>
4
<__main__.Something object at 0x7faac77c3978>
5
Run Code Online (Sandbox Code Playgroud)

现在,我想知道第一个例子,当我打电话时self.a,我正在访问什么?它不是一个类变量,因为我似乎无法改变它的值.它也不是一个实例变量,因为它似乎在同一个类的不同对象之间共享.你怎么称呼它?

这是一个我正以错误方式使用的类变量吗?我知道cls如果一个约定的名称,所以也许我真正访问一个类变量,但我无法更改其值,因为我没有用@classmethod装饰器装饰该方法.

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

Dan*_*man 5

发生的事情是self.a指在不同时间的件事.

如果名称不存在实例变量,Python将查找该类的值.因此,检索到的值self.a将是类变量.

但是当设置属性via时self,Python将始终设置实例变量.所以现在self.a是一个新的实例变量,其值等于类变量+ 1.该属性隐藏了class属性,您不能再self通过类访问它.

(一个小问题,与问题无关:你永远不应该直接访问双下划线方法.而不是打电话something2.__str__(),打电话str(something2)等)