类属性和实例属性有什么区别?

2022-01-13 00:00:00 python attributes member-variables

问题描述

以下之间是否有任何有意义的区别:

Is there any meaningful distinction between:

class A(object):
    foo = 5   # some default value

对比

class B(object):
    def __init__(self, foo=5):
        self.foo = foo

如果您要创建大量实例,这两种样式在性能或空间要求上是否有任何差异?看代码的时候,有没有觉得这两种风格的含义有很大的不同?

If you're creating a lot of instances, is there any difference in performance or space requirements for the two styles? When you read the code, do you consider the meaning of the two styles to be significantly different?


解决方案

存在显着的语义差异(超出性能考虑):

There is a significant semantic difference (beyond performance considerations):

  • 在实例上定义属性时(这是我们通常所做的),可以引用多个对象.每个人都有一个完全独立的该属性版本.
  • 当在类上定义属性时,只有一个底层对象被引用,所以如果对该类的不同实例的操作都尝试设置/(追加/扩展/插入/等.) 属性,然后:
    • 如果属性是内置类型(如int、float、boolean、string),对一个对象的操作将覆盖(破坏)该值
    • 如果属性是可变类型(如列表或字典),我们会得到不必要的泄漏.
    • when the attribute is defined on the instance (which is what we usually do), there can be multiple objects referred to. Each gets a totally separate version of that attribute.
    • when the attribute is defined on the class, there is only one underlying object referred to, so if operations on different instances of that class both attempt to set/(append/extend/insert/etc.) the attribute, then:
      • if the attribute is a builtin type (like int, float, boolean, string), operations on one object will overwrite (clobber) the value
      • if the attribute is a mutable type (like a list or a dict), we will get unwanted leakage.

      例如:

      >>> class A: foo = []
      >>> a, b = A(), A()
      >>> a.foo.append(5)
      >>> b.foo
      [5]
      >>> class A:
      ...  def __init__(self): self.foo = []
      >>> a, b = A(), A()
      >>> a.foo.append(5)
      >>> b.foo    
      []
      

相关文章