Mar*_*oth 4 python metaprogramming multiple-inheritance mixins
我有许多类被其他类包装以添加新功能.
不幸的是,包装类没有为它们包装的类实现传递函数,因此包装器不能与原始类互换使用.
我想动态创建包含包装器和原始类的功能的类.
我的想法是创建一个混合类并使用工厂将其应用于现有类以动态创建新的双用途类.这应该允许我编写混合一次,并且混合类用于通过一个对象从混合中提供原始功能或增强功能.
这是我追求的事情:
class A:
def __init__(self):
self.name = 'A'
def doA(self):
print "A:", self.name
class B(A):
def __init__(self):
self.name = 'B'
def doB(self):
print "B:", self.name
class C(A):
def __init__(self):
self.name = 'C'
def doC(self):
print "C:", self.name
class D:
def doD(self):
print "D:", self.name
class BD(B,D):
pass
def MixinFactory(name, base_class, mixin):
print "Creating %s" % name
return class(base_class, mixin) # SyntaxError: invalid syntax
a, b, c, d, bd = A(), B(), C(), D(), BD()
bd2 = MixinFactory('BD2', B, D)()
cd = MixinFactory('CD', C, D)()
a.doA() # A: A
b.doA() # A: B
b.doB() # B: B
c.doA() # A: C
c.doC() # C: C
bd.doA() # A: B
bd.doB() # B: B
bd.doD() # D: B
bd2.doA() # A: B
bd2.doB() # B: B
bd2.doD() # D: B
cd.doA() # A: C
cd.doC() # C: C
cd.doD() # D: C
Run Code Online (Sandbox Code Playgroud)
问题是,显然你不能只从函数返回一个类.忽略语法错误,上面的代码确实显示了我想要实现的内容.
我玩了三个参数变体,type()但无法让它工作,所以我不确定这是否是正确的方法.
我假设在Python 中创建这种类型的混合工厂是可能的,那么实现它需要了解什么呢?
正如Niklas R评论的那样,回答Python动态继承的问题:如何在实例创建时选择基类?为我的查询提供了解决方案,但Ben的答案提供了更好的原因解释.
实际上你可以从一个函数返回一个类.您的语法错误是您正在使用class 关键字,就好像它是您可以调用的函数一样.
请记住,所有类块都是创建一个新类,然后将您选择的名称绑定到它(在当前范围内).所以只需在你的函数中放一个类块,然后返回类!
def mixinFactory(name, base, mixin):
class _tmp(base, mixin):
pass
_tmp.__name__ = name
return _tmp
Run Code Online (Sandbox Code Playgroud)
如ejucovy所述,您也可以type直接致电:
def mixinFactory(name, base, mixin):
return type(name, (base, mixin), {})
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为它(通常)是一个类块实际上做的事情; 它将您在类块中定义的所有名称收集到字典中,然后传递类的名称,基类的元组和字典,type以构造新类.
但是,type它只不过是默认的元类.类是其他所有对象,是类的实例.大多数类都是实例type,但是如果涉及另一个元类,则应该调用它而不是type,就像你不会调用object创建类的新实例一样.
你的mixin(大概)没有定义元类,所以它应该与作为子类的任何元类兼容type.所以你可以使用任何类base:
def mixinFactory(name, base, mixin):
return base.__class__(name, (base, mixin), {})
Run Code Online (Sandbox Code Playgroud)
然而,S.Lott的评论看起来似乎是这个问题的最佳"答案",除非你的mixin工厂做的事情比创建一个新类更复杂.与任何提出的动态类创建变体相比,这更清晰,更少输入:
class NewClass(base, mixin):
pass
Run Code Online (Sandbox Code Playgroud)
您可以在任何地方使用类声明,并且类声明可以引用变量以进行子类化。至于类名,它只是.__name__类对象上的属性。所以:
def MixinFactory(name, base_class, mixin):
print "Creating %s" % name
class kls(base_class, mixin):
pass
kls.__name__ = name
return kls
Run Code Online (Sandbox Code Playgroud)
应该这样做。
对于单行代码,三参数type函数也应该起作用:
def MixinFactory(name, base_class, mixin):
return type(name, (base_class, mixin), {})
Run Code Online (Sandbox Code Playgroud)