【问题标题】:Changing a class attribute within __init__在 __init__ 中更改类属性
【发布时间】:2015-12-08 06:07:16
【问题描述】:

我正在查看 Stack Overflow 问题 Counting instances of a class?,我不确定为什么该解决方案有效,而使用简单加法的解决方案无效。我想这更多是关于如何存储和访问类与实例变量的问题。

这是我认为应该可以工作的代码,但会为每个 id 生成 4

class foo():
      num = 3    # trying 3 instead of 0 or 1 to make sure the add is working

      def __init__(self):
        self.num += 1
        self.id = self.num

f = foo()
g = foo()

print f.id    # 4
print g.id    # 4

self.num +=1 语句有些工作(正在添加,但没有赋值)。

到底发生了什么导致此分配在这里失败,而 itertools.count 分配在另一个问题的解决方案中成功?

【问题讨论】:

    标签: python python-2.7 python-internals


    【解决方案1】:

    整数不实现__iadd__(就地添加,用于+=),因为它们是不可变的。解释器回退到标准分配和__add__,所以行:

    self.num += 1
    

    变成:

    self.num = self.num + 1
    

    如您所料,在右侧您通过self.num 获得foo.num(即3),但这里有趣的是分配给实例属性num 阴影类属性。所以该行实际上相当于:

    self.num = foo.num + 1  # instance attribute equals class attribute plus one
    

    所有实例都以self.num == 4结尾,而仍然是foo.num == 3。相反,我怀疑你想要的是:

    foo.num += 1  # explicitly update the class attribute
    

    或者,您可以将其实现为@classmethod,更明确地处理该类:

    class Foo():  # note naming convention
    
        num = 3
    
        def __init__(self):
            self.increment()
            self.id = self.num  # now you're still accessing the class attribute
    
        @classmethod
        def increment(cls):
            cls.num += 1
    

    【讨论】:

    • 或者,self.__class__.num += 1
    • @robert 可以,但我觉得有点尴尬
    【解决方案2】:

    self.num += 1 基本上意味着'取self.num 的值,增加它,然后分配给self.num

    如果没有对应的实例变量,则在self 上查找属性将找到类变量。但是,assigning 将始终写入实例变量。所以,这试图找到一个实例 var,失败,回退到一个类 var,获取值,增加它,然后将 分配给一个实例 var

    链接问题的答案有效的原因是没有进行分配;他们直接在类变量上调用next(),它的值发生了变化,但名称没有重新分配。

    【讨论】:

      【解决方案3】:

      增强赋值不会更新类变量。它这样做:

      tmp = self.num
      self.num = tmp.__iadd__(1)
      

      注意分配回self.num 那里!因此,您的 class 属性保持不变。整数的object.__iadd__() method 不能就地改变数字,因为整数是不可变的,所以foo.num 永远不会改变。

      你需要显式引用类变量:

      foo.num += 1
      

      self.__class__.num += 1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-27
        • 1970-01-01
        • 2013-01-21
        • 2011-06-16
        • 1970-01-01
        • 2019-03-02
        • 2016-11-10
        相关资源
        最近更新 更多