Python 在 __new__ 中创建对象期间设置属性
Posted
技术标签:
【中文标题】Python 在 __new__ 中创建对象期间设置属性【英文标题】:Python set attributes during object creation in __new__ 【发布时间】:2019-06-18 21:33:19 【问题描述】:当使用 __new__ 自定义创建元类时,我们可以将属性传递给 type().__new__ 方法,该方法将在对象返回之前对其进行设置,例如
class Foo(type):
def __new__(cls, name, bases, attrs):
attrs['customAttr'] = 'someVal'
return type.__new__(cls, name, bases, attrs)
这样:
>> Foo.__dict__
'customeAttr': 'someVal', ...
但是我不知道如何对普通(非元)类执行相同操作,这会在使用 __setattr__ 时导致问题:
class Bar(object):
def __new__(cls, someVal):
obj = object().__new__(cls) # cant pass custom attrs
obj.customAttr = someVal # obj is already a Bar and invokes __setattr__
return obj
def __setattr__(*args): raise Exception('read-only class')
不幸的是:
>>> Bar(42)
...
Exception: read-only class
在 Bar 的 __new__ 中,我从 object() 中获取了一个完全成熟的类实例,并且任何属性访问都通过正常的查找规则,在本例中调用 __setattr__。元类 Foo 避免了这种情况,因为 type() 会在低级创建期间返回实例之前设置属性,而 object() 不会。
有没有一种方法可以将属性传递给 object() 或者我可以使用另一种类型作为从 __new__ 返回的实例,它允许在属性成为完整的类实例之前设置属性?我对在创建实例后设置 __class__ 之类的解决方案不感兴趣。
【问题讨论】:
【参考方案1】:您必须通过调用super
或root object
__setattr__
来明确绕过您自己类的__setattr__
。所以你会改变:
obj.customAttr = someVal
到:
object.__setattr__(obj, 'customAttr', someVal)
一种不太通用的方法(不适用于基于__slots__
的类)是使用dict
操作直接分配给__dict__
:
obj.__dict__['customAttr'] = someVal # Equivalently: vars(obj)['customAttr'] = someVal
第一种方法是the newly __slots__
-ed uuid.UUID
现在使用的; before it became __slots__
-ed, it used the second approach。在这两种情况下,这都是必需的,因为它们使用了相同的 __setattr__
技巧来使类型尽可能不可变(无需为子类化 tuple
、a la typing.NamedTuple
而烦恼)。
【讨论】:
以上是关于Python 在 __new__ 中创建对象期间设置属性的主要内容,如果未能解决你的问题,请参考以下文章