如何在 Python 中创建 Mixin 工厂?
我有许多类被其他类包装以添加新功能。
不幸的是,包装器类没有为它们所包装的类实现传递函数,因此包装器不能与原始类互换使用。
我想动态创建包含包装器和原始类的功能的类。
我的想法是创建一个混合类并使用工厂将其应用到现有类以动态创建新的双重用途类。这应该允许我编写一次混合,并且混合类可用于通过一个对象提供混合中的原始功能或增强功能。
这就是我所追求的事情:
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
问题是,显然你不能从函数返回一个类。尽管忽略语法错误,上面的代码确实显示了我想要实现的目标。
我尝试了 type()
的三个参数变体,但无法使其工作,所以我不确定这是否是正确的方法。
我假设在 Python 中创建这种类型的混合工厂是可能的,那么我需要了解什么才能实现它呢?
正如 Niklas R 评论的那样,这个答案问题Python 动态继承:如何在创建实例时选择基类? 为我的查询提供了解决方案,但是 Ben 的回答在这里提供了更好的解释。
I have a number of classes which are wrapped by other classes to add new functionality.
Unfortunately, the wrapper classes don't implement pass through functions for the classes they are wrapping, so the wrapper cannot be used interchangeably with the original class.
I would like to dynamically create classes that contain the functionality of both the wrapper and the original class.
The idea I had was to create a mix-in class and use a factory to apply it to the existing class to create a new dual use class dynamically. This should allow me to write the mix-in once, and for the mixed class to be used to provide either the original functionality or the enhanced functionality from from the mix-in via one object.
This is the sort of thing I'm after:
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
The problem is that obviously that you can't just return a class from a function. Ignoring the syntax error though, the above code does show what I'm trying to achieve.
I had a play with the three argument variant of type()
but couldn't get that to work, so I'm not sure if that is the right approach.
I assume that creating a mix-in factory of this type is possible in Python, so what do I need to understand to implement it?
As Niklas R commented, this answer to the question Python dynamic inheritance: How to choose base class upon instance creation? provides the solution to my query, but Ben's answer here provides a better explanation of why.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
实际上你可以从函数返回一个类。您的语法错误是您使用类关键字,就好像它是您可以调用的函数一样。
请记住,所有类块都是创建一个新类,然后将您选择的名称绑定到它(在当前范围内)。因此,只需在函数中放置一个类块,然后返回该类即可!
正如ejucovy所述,您还可以直接调用
type
:这有效,因为它(通常)类块实际上做了什么;它将您在类块中定义的所有名称收集到字典中,然后将类的名称、基类的元组和字典传递给
type
来构造新类。然而,
type
只不过是默认元类。类与其他事物一样是对象,并且是类的实例。大多数类都是type
的实例,但如果涉及另一个元类,您应该调用它而不是type
,就像您不会调用object
一样创建类的新实例。您的 mixin(大概)没有定义元类,因此它应该与
type
子类的任何元类兼容。因此,您可以使用任何base
的类:但是,S.Lott 的评论确实似乎是这个问题的最佳“答案”,除非您的 mixin 工厂正在做任何比仅仅创建一个更复杂的事情新班级。这比任何建议的动态类创建变体都更清晰且更少的打字:
Actually you can return a class from a function. Your syntax error is that you're using the class keyword as if it were a function you can invoke.
Remember that all a class block for is create a new class and then bind the name you chose to it (in the current scope). So just put a class block inside your function, then return the class!
As noted by ejucovy, you can also call
type
directly:This works because it's (usually) what a class block actually does; it collects all the names you define in the class block into a dictionary, then passes the name of the class, a tuple of the base classes, and the dictionary on to
type
to construct the new class.However,
type
is nothing more than the default metaclass. Classes are objects like everything else, and are instances of a class. Most classes are instances oftype
, but if there's another metaclass involved you should call that instead oftype
, just as you wouldn't callobject
to create a new instance of your class.Your mixin (presumably) doesn't define a metaclass, so it should be compatible with any metaclass that is a subclass of
type
. So you can just use whatever the class ofbase
is:However, S.Lott's comment really seems like the best "answer" to this question, unless your mixin factory is doing anything more complicated than just creating a new class. This is much clearer AND less typing than any of the dynamic class creation variants proposed:
您可以在任何地方进行类声明,并且类声明可以引用用于子类化的变量。至于类名,它只是类对象上的
.__name__
属性。所以:应该这样做。
对于单行代码,三参数
type
函数也应该起作用:You can have class declarations anywhere, and class declarations can refer to variables for subclassing. As for the class name, it's just the
.__name__
attribute on the class object. So:should do it.
For a one-liner, the three-argument
type
function should work too: