繁体   English   中英

元类__init__中setattr()的异常行为

[英]Unexpected behavior of setattr() inside Metaclass __init__

这是一个打算提供自定义__init__的基本Metaclass

class D(type):
    def __init__(cls, name, bases, attributes):
        super(D, cls).__init__(name, bases, attributes)
        for hook in R.registered_hooks:
            setattr(cls, hook.__qualname__, hook)

for循环遍历函数列表,并为每个函数调用setattr(cls, hook.__qualname__, hook)

这是使用上述元类的类:

class E(metaclass=D):
    def __init__(self):
        pass

奇怪的是:

E().__dict__   prints {}

但是当我打电话

`E.__dict__   prints {'f1': <function f1 at 0x001>, 'f2': <function f2 at 0x002>}`

我期望将这些函数作为属性添加到实例属性中 ,因为__init__为Class提供了自定义初始化,但是似乎属性已添加到Class属性中

在这种情况下,这是什么原因导致的?如何在实例中添加属性? 谢谢!

它们被添加为实例属性。 但是,该实例是class ,作为元类的实例。 您没有为E定义__init__方法; 您正在定义type用于初始化E本身的方法。

如果只想将属性添加到E的实例,那么您的工作级别错误; 您应该定义一个mixin并为此使用多重继承。

为了在对象obj的实例化上调用__init__ ,您需要定义type(obj).__init__ 通过使用元类,您定义了type(type(obj)).__init__ 您的工作水平错误。

在这种情况下,您只需要继承,而不需要元类。

class D():
    def __init__(self, *args):
        print('D.__init__ was called')

class E(D):
    pass

e = E() # prints: D.__init__ was called

请注意,您仍然会发现e.__dict__为空。

print(e.__dict__) # {}

这是因为您的实例没有属性,方法在类中存储和查找。

如果使用元类,则意味着要更改类的定义,这将间接影响该类实例的属性。 假设您确实要执行此操作:

您正在创建自定义__init__方法。 与普通实例化一样,在已经创建的对象上调用__init__ 通常,当您对元类进行有意义的操作时,需要在实例化之前将其添加到类的字典中,这是通过__new__方法完成的,以避免子类中可能出现的问题。 它看起来应该像这样:

class D(type):

    def __new__(cls, name, bases, dct):
        for hook in R.registered_hooks:
            dct[hook.__qualname__] = hook
        return super(D, cls).__new__(cls, name, bases, dct)

这不会修改该类实例的__dict__ ,但是实例的属性解析也会查找类属性。 所以,如果你加foo作为一个属性E在元类, E().foo将返回预期值,即使它是不可见的E().__dict__

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM