来自元类工厂的多重继承
Posted
技术标签:
【中文标题】来自元类工厂的多重继承【英文标题】:Multi inheritance from metaclasses factories 【发布时间】:2012-02-15 06:06:54 【问题描述】:我希望SuperClass12
继承自SuperClass1
和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()
很遗憾我遇到了这个错误:
TypeError: 调用元类基类时出错元类冲突:派生类的元类必须是其所有基类的元类的(非严格)子类
但我不明白为什么,因为我的派生类SuperClass12
的元类myMultiMeta
确实是其所有基类(SuperClass1,SUperClass2)
的元类(MyMetaClass1,MyMetaClass2)
的子类。
【问题讨论】:
【参考方案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】:请记住,getClass1
和 getClass2
返回元类的新实例。因此,当您设置__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 功能。 :-) 这通常表明您正在做一些可能以其他方式做得更好的事情。例如,您为什么要使用工厂,而不是仅仅以正常方式定义类?我见过类工厂有一些用处,但我认为我从未在野外见过元类工厂。
【讨论】:
以上是关于来自元类工厂的多重继承的主要内容,如果未能解决你的问题,请参考以下文章