Python:类中的静态对象

3
我想知道如何在Python类中正确地保留一个静态对象。在这种情况下,我想要一个静态字典。
以下是我需要的一个简单例子:
class dTest:
    # item I want to be static
    d = {"First":1}

>>> a = dTest()
>>> a.d
{'First': 1}
>>> dTest.d["Second"] = 2
>>> a.d["Third"] = 3
>>> a.d
{'Second': 2, 'Third': 3, 'First': 1}
>>> dTest.d
{'Second': 2, 'Third': 3, 'First': 1}

现在如果我直接调用这个类并替换d为一个新的字典。
>>> dTest.d = {}
>>> a.d
{}

然而,如果我用一个新的字典替换a.d,我也希望能够拥有相同的功能。

>>> a.d = {"Fourth":4}
>>> a.d
{'Fourth': 4}
>>> dTest.d
{}

我现在期望的结果是dTest.d与a.d相同(其中dTest.d为{'Fourth': 4)}。

是否有适当的处理方法,或者我必须确保只有在通过dTest实例进行编辑时才能编辑对象?

谢谢!


1
使用 property 创建 getter 和 setter。 - JBernardo
尝试在更改a.d之后更改dTest.d,您会注意到a.d将不再随dTest.d一起更改。 - 2rs2ts
@JBernardo:当通过类访问d时,属性将无法工作... - bruno desthuilliers
如果在元类下创建,它就会有作用。 - JBernardo
@JBernardo 是的,确实这是一个可能的解决方案 - 即使可能有点过度杀伤 <g> - bruno desthuilliers
2个回答

8

在处理类时,有两种不同类型的变量:实例变量和类变量。

类变量可从类的所有实例以及类本身访问:

>>> class Foo(object):
...    class_var = {'one': 1}
...
>>> Foo.class_var
{'one': 1}
>>> a, b = Foo(), Foo()
>>> a.class_var
{'one': 1}
>>> b.class_var
{'one': 1}
>>> a.class_var is b.class_var 
True # These are the same object
>>> 

实例变量只能从被分配给它们的特定实例中访问:
>>> class Foo(object):
...     def __init__(self):
...             self.instance_var1 = {'two': 2}
... 
>>> foo = Foo()
>>> foo.instance_var2 = {'three': 3}
>>> foo.instance_var1
{'two': 2}
>>> foo.instance_var2
{'three': 3}
>>> Foo.instance_var1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Foo' has no attribute 'instance_var1'

实例变量可以覆盖类变量:
>>> class Foo(object):
...     my_var = {'one': 1} # This a class variable
... 
>>> foo = Foo()
>>> foo.my_var = {'two': 2} # Override class my_var with instance my_var
>>> foo.my_var
{'two': 2}
>>> Foo.my_var
{'one': 1}
>>> foo.__class__.my_var # But you can still access the class variable like this.
{'one': 1}
>>> 

回答您的问题。如果您想修改“class”变量,您必须从“class”而不是实例设置它,因此:
dTest.d = {'blah': 'blah'}

或者

a.__class__.d = {'blah': 'blah'}

如果你只是执行

a.d = {'blah': 'blah'}

您创建了一个名为a的实例变量,它覆盖了具有相同名称的类变量。


谢谢您的快速回复!那很有道理! - flakes

2
您所使用的类中的字典是共享的,当您向d添加键值对时,无论是用a.d[key] = ...还是dTest.d[key] = ...,都不会改变d的引用,因此它仍然是一个共享的类属性。
但是如果您尝试将某些内容分配给a.d,例如a.d = 123a.d = [11,22],则会为实例a创建一个名为d的属性,a.d不再引用dType.d。请参阅赋值语句
注意:如果对象是类实例,并且属性引用出现在赋值运算符的两侧,则RHS表达式a.x可以访问实例属性或(如果不存在实例属性)类属性。 LHS目标a.x始终设置为实例属性,如果需要,将其创建。因此,a.x的两个出现不一定引用相同的属性:如果RHS表达式引用类属性,则LHS创建一个新的实例属性作为赋值的目标。
class Cls:
    x = 3             # class variable
inst = Cls()
inst.x = inst.x + 1   # writes inst.x as 4 leaving Cls.x as 3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接