来自元类工厂的多重继承

时间:2012-01-20 17:28:36

标签: python multiple-inheritance metaclass

我希望SuperClass12继承SuperClass1SuperClass2

def getClass1(): 
    class MyMetaClass1(type):
        def __new__(cls, name, bases, dct):
            print dct.get("Attr","")+"Meta1"
            return super(MyMetaClass1, cls).__new__(cls, name, bases, dct)
    return MyMetaClass1

def getClass2(): 
    class MyMetaClass2(type):
        def __new__(cls, name, bases, dct):
            print dct.get("Attr","")+"Meta2"
            return super(MyMetaClass2, cls).__new__(cls, name, bases, dct)
    return MyMetaClass2    

class SuperClass1():
    __metaclass__ = getClass1()
    def fun1(self):
        pass

class SuperClass2():
    __metaclass__ = getClass2()
    def fun2(self):
        pass

class MyClass1(SuperClass1):
    Attr = "MC1"

class MyClass2(SuperClass2):
    Attr = "MC2"

def getClass12(): 
    class myMultiMeta(getClass1(),getClass2()):
        pass
    return myMultiMeta

class SuperClass12(SuperClass1,SuperClass2):
#class SuperClass12(): gives no errors in class construction but then 
#fun1() and fun2() are not members of SuperClass12. 
    __metaclass__ = getClass12()

class MyClass12(SuperClass12):
    Attr = "MC12"

Instance = MyClass12()
Instance.fun1()
Instance.fun2()
遗憾的是我有这个错误:

  

TypeError:调用元类基类元类冲突时出错:派生类的元类必须是其所有基类的元类的(非严格)子类

但我无法理解为什么,因为我的派生类myMultiMeta的元类SuperClass12确实是其所有基础(MyMetaClass1,MyMetaClass2)的元类(SuperClass1,SUperClass2)的子类。

4 个答案:

答案 0 :(得分:3)

正如Michael Merickel所指出的,getClass()函数需要在每次调用时返回相同的对象才能继承。一个仅仅相同的类是不够好的。这是一种方法,滥用一个类使其像你的getClass()函数。由于类定义只执行一次,因此MyMetaClass1在返回时始终是同一个对象。

class getClass1(object):
    class MyMetaClass1(type):
        def __new__(cls, name, bases, dct):
            print dct.get("Attr","")+"Meta1"
            return super(MyMetaClass1, cls).__new__(cls, name, bases, dct)
    class __metaclass__(type):
        def __call__(cls):
            return cls.MyMetaClass1

您也可以这样做,使用真实函数并滥用可变默认参数来缓存类实例:

def getClass1(cls=[]):
    if not cls:
        class MyMetaClass1(type):
            def __new__(cls, name, bases, dct):
                print dct.get("Attr","")+"Meta1"
                return super(MyMetaClass1, cls).__new__(cls, name, bases, dct)
        cls.append(MyMetaClass1)
    return cls[0]

你会注意到一个反复出现的主题:滥用Python功能。 :-)这通常表明你正在做一些可能在其他方面做得更好的事情。例如,您为什么使用工厂,而不仅仅是以正常的方式定义类?我见过班级工厂有一些用途,但我不认为我曾经见过野外的元类工厂。

答案 1 :(得分:2)

请记住,getClass1getClass2会返回元类的新实例。因此,当您设置__metaclass__ = getClass1()时,这是与myMultiMeta继承的元类不同的元类。

答案 2 :(得分:1)

这是你想要的吗?

class MyMetaClass1(type):
    def __new__(cls, name, bases, dct):
        print dct.get("Attr","")+"Meta1"
        return super(MyMetaClass1, cls).__new__(cls, name, bases, dct)

class MyMetaClass2(type):
    def __new__(cls, name, bases, dct):
        print dct.get("Attr","")+"Meta2"
        return super(MyMetaClass2, cls).__new__(cls, name, bases, dct)

class SuperClass1():
    __metaclass__ = MyMetaClass1
    def fun1(self):
        pass

class SuperClass2():
    __metaclass__ = MyMetaClass2
    def fun2(self):
        pass

class MyClass1(SuperClass1):
    Attr = "MC1"

class MyClass2(SuperClass2):
    Attr = "MC2"

class MyMultiMeta(MyMetaClass1, MyMetaClass2):
    pass

class SuperClass12(SuperClass1, SuperClass2):
#class SuperClass12(): gives no errors in class construction but then 
#fun1() and fun2() are not members of SuperClass12. 
    __metaclass__ = MyMultiMeta

class MyClass12(SuperClass12):
    Attr = "MC12"

Instance = MyClass12()
Instance.fun1()
Instance.fun2()

执行命令

vic@ubuntu:~/Desktop$ python test.py 
Meta1
Meta2
MC1Meta1
MC2Meta2
Meta1
Meta2
MC12Meta1
MC12Meta2
vic@ubuntu:~/Desktop$ 

答案 3 :(得分:0)

我感谢谁,通过给出一些答案,帮助了我:

def getClass12(): 
     class myMultiMeta(SuperClass1.__metaclass__,SuperClass2.__metaclass__):
         pass
     return myMultiMeta
 class SuperClass12(SuperClass1,SuperClass2):
     __metaclass__ = getClass12()

是一个不太糟糕的解决方案!