【问题标题】:Calling class variable with self用 self 调用类变量
【发布时间】:2023-03-17 02:07:01
【问题描述】:

你是怎么想出这个有趣的(至少对我来说)例子的。

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 装饰器装饰方法。

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

【问题讨论】:

  • 好,内容丰富的问题​​!但是您能否编辑问题的第一行“我如何想出这个有趣的(至少对我而言)示例”。让人们能理解吗?

标签: python python-3.x instance-variables class-variables


【解决方案1】:

发生的情况是self.a 在不同的时间引用了两个 事物。

当一个名称不存在实例变量时,Python 将在该类上查找该值。因此,为self.a 检索到的值将是类变量。

但是当通过self设置一个属性时,Python会总是设置一个实例变量。所以现在self.a 是一个新的实例变量,它的值等于类变量 + 1。这个属性隐藏了类属性,你不能再通过self 访问,只能通过类访问。

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

【讨论】:

    【解决方案2】:

    丹尼尔·罗斯曼的回答清楚地解释了这个问题。以下是一些额外的观点,希望对您有所帮助。 您可以使用 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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-20
      • 1970-01-01
      • 2017-11-11
      • 1970-01-01
      • 1970-01-01
      • 2020-02-29
      • 2019-01-07
      • 1970-01-01
      相关资源
      最近更新 更多