我有一个奇怪的元类问题。我正在使用元类来动态创建一个继承自另一个超类的“兄弟”类,并将其作为原始类的属性赋值。以下是最小化设置:
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
我看不出这两种情况之间的区别。
答案 0 :(得分:5)
传递给类型的词典 sdct 包括__qualname__
,根据此PEP, repr 和 str 现在使用。
尝试添加
print(Child is Child.sibling) # False
print(Child.sibling.__name__) # "ChildSibling"
你会发现它确实是兄弟姐妹。
至于为什么sibling().x
抛出,同样的 sdct 也已包含Child.__init__
,最终为动态创建的新类型__init__
ChildSibling
1}}。在致电sibling()
期间,super()
电话会将课程解析为Child
并获得ChildSibling
的实例:
另请注意,除零参数形式外,super()不限于使用内部方法。两个参数形式完全指定参数并进行适当的引用。零参数形式仅适用于类定义,,因为编译器填写必要的详细信息以正确检索正在定义的类,以及访问普通方法的当前实例。
https://docs.python.org/3/library/functions.html#super
通过将第一个参数传递给方法实例来访问当前实例。
super() -> same as super(__class__, <first argument>)
错误在line 7210 of Object/typeobject.c处提出。
尝试使用以下内容删除__init__
中错误的__new__
del sdct['__init__']
现在
print(Child().sibling().x)
将打印3。
“通用”继承和元编程友好__init__
的解决方案是使用super()
的2参数形式:
def __init__(self):
super(self.__class__, self).__init__()