来自元类工厂的多重继承

发布于 2024-12-28 11:48:07 字数 1560 浏览 5 评论 0原文

我希望 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)

I want SuperClass12 to inherit from SuperClass1 and SuperClass2:

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()

sadly I've got this error:

TypeError: Error when calling the metaclass bases metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

but I cannot understand why, since the metaclass myMultiMeta of my derived class SuperClass12 indeed is a subclass of bothe the metaclasses (MyMetaClass1,MyMetaClass2) of all its bases (SuperClass1,SUperClass2).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

折戟 2025-01-04 11:48:07

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

As noted by Michael Merickel, the getClass() functions need to return the same object on each call for your inheritance to work. A class that is merely identical isn't good enough. Here's one way to do that, abusing a class to make it act like your getClass() functions. Since the class definition is only executed once, MyMetaClass1 is always the same object when returned.

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

You could also do it like so, using a real function and abusing a mutable default argument to cache the class instance:

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]

You will notice a recurring theme here: abuse of Python features. :-) That is usually a sign that you are doing something that maybe is done better some other way. For example, why are you using factories, rather than just defining the class the normal way? I've seen class factories have some use, but I don't think I've ever seen a metaclass factory in the wild.

笔落惊风雨 2025-01-04 11:48:07

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

Remember that getClass1 and getClass2 return a new instance of the metaclass. Thus when you set __metaclass__ = getClass1(), that is a different metaclass than the one inherited by myMultiMeta.

情域 2025-01-04 11:48:07

这是你想要的吗?

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$ 

Is this what you want?

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()

Run:

vic@ubuntu:~/Desktop$ python test.py 
Meta1
Meta2
MC1Meta1
MC2Meta2
Meta1
Meta2
MC12Meta1
MC12Meta2
vic@ubuntu:~/Desktop$ 
梦屿孤独相伴 2025-01-04 11:48:07

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

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

这是一个不错的解决方案!

I thank who, by giving some answers, helped me:

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

is a not so bad solution!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文