我有一个奇怪的元类问题。我正在使用一个元类来动态创建一个从另一个超类继承的“同级”类,并将其分配为原始类的一个属性。以下是最小设置:
class Meta(type):
def __new__(cls, name, parents, dct):
sdct = dct.copy()
dct['sibling'] = type(name+'Sibling', (Mom,), sdct)
return super().__new__(cls, name, (Dad,), dct)
class Mom:
def __init__(self):
self.x = 3
class Dad:
def __init__(self):
self.x = 4
class Child(metaclass=Meta):
def __init__(self):
super().__init__()
self.y = 1 # <<< added from feedback
print(Child().x) # 4
print(Child().sibling) # <class '__main__.Child'> | should be ChildSibling
print(Child().sibling().x) # should be 3 instead throws:
# TypeError: super(type, obj): obj must be an instance or subtype of type
print(Child().sibling().y) # should print 4
上面创建“兄弟”类似乎出了点问题,但是我不太确定是什么。我知道例如这将工作:
class ChildAbstract:
def __init__(self):
super().__init__()
ChildSibling = type('ChildSibling', (ChildAbstract, Mom), {})
Child = type('Child', (ChildAbstract, Dad), {'sibling': ChildSibling})
print(Child().sibling().x) # 3
我看不到这两种情况之间的区别。
传递给type的字典sdct包括,根据此PEP,这是repr和str现在使用的字典。__qualname__
尝试添加
print(Child is Child.sibling) # False
print(Child.sibling.__name__) # "ChildSibling"
您会发现它确实是兄弟姐妹。
至于sibling().x
抛出的原因,已经包含了相同的sdctChild.__init__
,它最终以__init__
动态创建的new type结束ChildSibling
。在调用期间sibling()
,super()
将类解析为,Child
并为其提供了的实例ChildSibling
:
还要注意,除零参数形式外,super()不限于在内部方法中使用。两个参数形式准确地指定了参数并进行了适当的引用。零参数形式仅在类定义内起作用,因为编译器会填充必要的详细信息以正确检索要定义的类,以及为常规方法访问当前实例。
https://docs.python.org/3/library/functions.html#super
通过将第一个参数传递给方法作为实例来完成对当前实例的访问。
super() -> same as super(__class__, <first argument>)
在Object / typeobject.c的第7210行引发错误。
尝试使用以下方法消除__init__
您的错误__new__
:
del sdct['__init__']
现在
print(Child().sibling().x)
将打印3。
解决“泛型”继承和元编程更友好的方法__init__
是使用以下2个参数形式super()
:
def __init__(self):
super(self.__class__, self).__init__()
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句