Buc*_*uck 4 python inheritance metaclass
我有一个奇怪的元类问题.我正在使用元类来动态创建一个继承自另一个超类的"兄弟"类,并将其作为原始类的属性赋值.以下是最小化设置:
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
Run Code Online (Sandbox Code Playgroud)
随着"兄弟"课程的创作,上面似乎出现了一些问题,但我不太确定是什么.我知道例如这会起作用:
class ChildAbstract:
def __init__(self):
super().__init__()
ChildSibling = type('ChildSibling', (ChildAbstract, Mom), {})
Child = type('Child', (ChildAbstract, Dad), {'sibling': ChildSibling})
print(Child().sibling().x) # 3
Run Code Online (Sandbox Code Playgroud)
但我看不出两种情况之间的区别.
字典sdct传递给type includes __qualname__,根据这个PEP,repr和str现在使用了.
尝试添加
print(Child is Child.sibling) # False
print(Child.sibling.__name__) # "ChildSibling"
Run Code Online (Sandbox Code Playgroud)
你会发现它确实是兄弟姐妹.
至于为什么sibling().x抛出,同样的sdct也已经包含Child.__init__,它最终是__init__动态创建的新类型ChildSibling.在对调用sibling()的super()调用期间,将类解析为,Child并且给出了以下实例ChildSibling:
另请注意,除零参数形式外,super()不限于使用内部方法.两个参数形式完全指定参数并进行适当的引用.零参数形式仅适用于类定义,因为编译器填写必要的细节以正确检索正在定义的类,以及访问普通方法的当前实例.
https://docs.python.org/3/library/functions.html#super
通过将第一个参数传递给method as instance来完成对当前实例的访问.
super() -> same as super(__class__, <first argument>)
在Object/typeobject.c的第7210行引发错误.
尝试删除__init__你的错误__new__:
del sdct['__init__']
Run Code Online (Sandbox Code Playgroud)
现在
print(Child().sibling().x)
Run Code Online (Sandbox Code Playgroud)
将打印3.
"泛型"继承和元编程更友好的解决方案__init__是使用以下2参数形式super():
def __init__(self):
super(self.__class__, self).__init__()
Run Code Online (Sandbox Code Playgroud)