繁体   English   中英

如何在Python中创建Mixin工厂?

[英]How do I create a Mixin factory in Python?

我有许多类,它们被其他类包装以添加新功能。

不幸的是,包装器类没有为其包装的类实现传递函数,因此包装器不能与原始类互换使用。

我想动态创建同时包含包装程序和原始类功能的类。

我的想法是创建一个混合类,并使用工厂将其应用于现有类,以动态创建一个新的双重用途类。 这应该允许我编写一次混入,并使用混合类通过一个对象从混入中提供原始功能或增强功能。

这是我所追求的:

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在这里的答案为为什么提供了更好的解释。

实际上,您可以从函数返回类。 您的语法错误是您正在使用class 关键字 ,就好像它是可以调用的函数一样。

请记住,所有的类块都是创建一个新类,然后将您选择的名称绑定到它(在当前作用域中)。 因此,只需将一个类块放入您的函数中,然后返回该类!

def mixinFactory(name, base, mixin):
    class _tmp(base, mixin):
        pass
    _tmp.__name__ = name
    return _tmp

ejucovy所述 ,您还可以直接调用type

def mixinFactory(name, base, mixin):
    return type(name, (base, mixin), {})

之所以有效,是因为(通常)类块实际上是在做什么; 它将您在类块中定义的所有名称收集到字典中,然后传递类的名称,基类的元组和字典以进行type以构造新的类。

但是, type只是默认的metaclass 类是与其他所有对象一样的对象,并且是类的实例。 大多数类都是type实例,但是如果涉及另一个元类,则应该调用它而不是type ,就像您不会调用object来创建类的新实例一样。

您的mixin(大概)未定义元类,因此它应与type的子类的任何元类兼容。 因此,您可以使用任何base类:

def mixinFactory(name, base, mixin):
    return base.__class__(name, (base, mixin), {})

但是,S.Lott的评论确实似乎是该问题的最佳“答案”,除非您的mixin工厂所做的事情不只是创建一个新类而已。 与提出的任何动态类创建变体相比,这更清晰,而且键入更少:

class NewClass(base, mixin):
    pass

您可以在任何地方使用类声明,并且类声明可以引用变量进行子类化。 至于类名,它只是类对象上的.__name__属性。 所以:

def MixinFactory(name, base_class, mixin):
  print "Creating %s" % name
  class kls(base_class, mixin):
    pass
  kls.__name__ = name
  return kls

应该做。

对于单行代码,三参数type函数也应该起作用:

def MixinFactory(name, base_class, mixin):
  return type(name, (base_class, mixin), {})

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM