Python的"class is a dict"理论和添加类变量的后果



只是出于好奇,我在Python类上玩__dict__属性。

我在某个地方读到python中的"class"是一种dict,在类实例上调用__dict__将该实例转换为dict……我觉得"很酷!我可以使用它!"

但这让我对这些行动的正确性和安全性产生了怀疑。

例如,如果我这样做:

class fooclass(object):
    def __init__(self, arg):
        self.arg1 = arg
p = fooclass('value1')
print(p.__dict__)
p.__dict__['arg2'] = 'value2'
print(p.__dict__)
print(p.arg2)

我有这个:

>>>{'arg1': 'value1'}
>>>{'arg1': 'value1', 'arg2': 'value2'}
>>>value2

这很好,但是:

  1. fooclass还有1个属性吗?我怎么能确定呢
  2. 这样添加属性安全吗
  3. 你有没有遇到过这种方法派上用场的案例
  4. 我发现我不能做fooclass.__dict__['arg2'] = 'value2'。。那么,为什么类和实例之间存在这种差异呢

您正在更改实例的属性。从__dict__中添加和删除正是大多数自定义类实例所发生的情况。

例外情况是当您有一个使用__slots__的类时;这种类的实例不具有__dict__属性,因为属性以不同的方式存储。

Python是一种成年人自愿使用的语言;在任何情况下都无法防止使用__dict__向实例添加属性,因此将它们添加到字典或使用setattr()也没有什么区别。

当您想要使用现有的dict方法来访问或更改属性时,访问__dict__非常有用;可以使用dict.update(),例如:

def Namespace(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

当尝试读取实例上的属性时,这也很有帮助,因为类上有相应的数据描述符;要绕过后者,可以访问实例上的__dict__以获取属性。您还可以使用它来测试实例上的属性,并忽略类或基类可能定义的任何内容。

对于fooclass.__dict__;您将与类的实例混淆。它们是单独的对象。类是不同类型的对象,ClassObj.__dict__只是一个代理对象;您仍然可以在类上使用setattr()来添加任意属性:

setattr(fooclass, 'arg2', 'value2')

或直接设置属性:

fooclass.arg2 = value2

类需要有一个__dict__代理,因为实际的__dict__属性是一个描述符对象,用于在实例上提供相同的属性。请参阅__dict__是什么__Python类的dict__属性?

有关Python对象如何工作的详细信息,请参阅Datamodel参考文档。

最新更新