【问题标题】:Multi inheritance from metaclasses factories来自元类工厂的多重继承
【发布时间】:2012-02-15 06:06:54
【问题描述】:

我希望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: 调用元类基类时出错元类冲突:派生类的元类必须是其所有基类的元类的(非严格)子类

但我不明白为什么,因为我的派生类SuperClass12 的元类myMultiMeta 确实是其所有基类(SuperClass1,SUperClass2) 的元类(MyMetaClass1,MyMetaClass2) 的子类。

【问题讨论】:

    标签: python multiple-inheritance metaclass


    【解决方案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$ 
    

    【讨论】:

    • 是的,这是所需的输出,现在我想知道为什么有些人定义返回元类的函数,就像我尝试使用 getClass1()、getClass2() 和 getClass12() 一样?我的代码有什么问题?
    • @jimifiki,坦率地说 - 我不知道 :)。我只是试图清除你的这些函数的代码。
    【解决方案2】:

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

    【讨论】:

    • 是的,但是“元类工厂”对于多继承来说是一个糟糕的解决方案。 “元类工厂”有什么用?
    • 这对很多事情都有好处,但是由于已经讨论过的问题,堆叠工厂不能以您的方式完成。更好的选择是将它变成一个可以抓取当前元类的类装饰器,并创建一个从它们继承的新元类,然后在您正在装饰的类上设置这个新元类。
    【解决方案3】:

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

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

    是一个不错的解决方案!

    【讨论】:

      【解决方案4】:

      正如 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 功能。 :-) 这通常表明您正在做一些可能以其他方式做得更好的事情。例如,您为什么要使用工厂,而不是仅仅以正常方式定义类?我见过类工厂有一些用处,但我认为我从未在野外见过元类工厂。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-26
        • 2023-04-08
        • 2018-07-27
        • 2018-01-19
        • 1970-01-01
        • 2012-11-16
        • 2010-09-20
        • 1970-01-01
        相关资源
        最近更新 更多