python元类继承问题

时间:2016-03-30 20:57:59

标签: 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

上面似乎出现了'兄弟'课程的错误,但我不太确定是什么。我知道例如这可行:

class ChildAbstract:
    def __init__(self):
        super().__init__()

ChildSibling = type('ChildSibling', (ChildAbstract, Mom), {})
Child = type('Child', (ChildAbstract, Dad), {'sibling': ChildSibling})
print(Child().sibling().x) # 3

我看不出这两种情况之间的区别。

1 个答案:

答案 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__()