【发布时间】:2018-07-20 22:27:42
【问题描述】:
我正在尝试使用 X.__dict__['x'] += 1 之类的东西直接修改类 __dict__ 中的值。不可能进行这样的修改,因为类__dict__ 实际上是一个不允许直接修改值的mappingproxy 对象。尝试直接修改或等效的原因是我试图将类属性隐藏在具有相同名称的元类上定义的属性后面。这是一个例子:
class Meta(type):
def __new__(cls, name, bases, attrs, **kwargs):
attrs['x'] = 0
return super().__new__(cls, name, bases, attrs)
@property
def x(cls):
return cls.__dict__['x']
class Class(metaclass=Meta):
def __init__(self):
self.id = __class__.x
__class__.__dict__['x'] += 1
此示例显示了为 Class 的每个实例创建自动递增 ID 的方案。 __class__.__dict__['x'] += 1 行不能被 setattr(__class__, 'x', __class__.x + 1) 替换,因为 x 是 property,在 Meta 中没有设置器。它只会将 TypeError 从 mappingproxy 更改为 AttributeError 从 property。
我试过搞乱__prepare__,但没有效果。 type 中的实现已经为命名空间返回了一个可变的dict。不可变的mappingproxy 似乎设置在type.__new__ 中,我不知道如何避免。
我还尝试将整个 __dict__ 引用重新绑定到可变版本,但同样失败:https://ideone.com/w3HqNf,这意味着 mappingproxy 可能不是在 type.__new__ 中创建的。
如何直接修改类dict 的值,即使被元类属性遮蔽?虽然它可能实际上是不可能的,但setattr 能够以某种方式做到这一点,所以我希望有一个解决方案。
我的主要要求是有一个似乎是只读的类属性,并且在任何地方都不使用其他名称。我并不完全赞同将元类 property 与同名类 dict 条目一起使用的想法,但这通常是我在常规实例中隐藏只读值的方式。
编辑
我终于弄清楚了__dict__ 类在哪里变得不可变。它在Data Model 参考的"Creating the Class Object" 部分的最后一段中进行了描述:
当
type.__new__创建一个新类时,作为命名空间参数提供的对象被复制到一个新的有序映射中,而原始对象被丢弃。新副本包装在只读代理中,成为类对象的__dict__属性。
【问题讨论】:
标签: python python-3.x class