python - 如何在 Python 中创建 Mixin 工厂?

标签 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

问题很明显,您不能只从函数返回一个类。虽然忽略了语法错误,但上面的代码确实显示了我想要实现的目标。

我玩过 type() 的三个参数变体,但无法让它工作,所以我不确定这是否是正确的方法。

我假设在 Python 中可以创建这种类型的混合工厂,那么我需要了解什么才能实现它?


作为Niklas R评论,this answer问题Python dynamic inheritance: How to choose base class upon instance creation?为我的查询提供了解决方案,但是 Ben此处的回答更好地解释了原因。

最佳答案

实际上你可以从一个函数中返回一个类。您的语法错误是您正在使用 keyword 类,就好像它是您可以调用的函数一样。

请记住,所有的类 block 都是创建一个新类,然后将您选择的名称绑定(bind)到它(在当前范围内)。所以只需在您的函数中放置一个类 block ,然后返回该类!

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), {})

这是可行的,因为它(通常)是类 block 的实际作用;它将您在类 block 中定义的所有名称收集到一个字典中,然后将类的名称、基类的元组和字典传递给 type 以构造新类。

但是,type 只不过是默认元类。类和其他任何东西一样都是对象,并且是类的实例。大多数类都是 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

关于python - 如何在 Python 中创建 Mixin 工厂?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9087072/

相关文章:

Python - 使用 httplib 来 PUT JSON 数据

c++ - has_member_of_type - C++ 中的模板元编程

ruby-on-rails - 如何在不更改原始类的情况下替换 belongs_to 关联

python - 使用python3.6类型错误: an integer is required

python - AttributeError ("module ' apache_beam.io.gcp.internal.clients.storage'没有属性 'StorageV1'“)

c++ - 如何从多个继承的类对象中分配 unique_ptr<base>?

c++ - 抽象基类谜题

python - 如何继承 QTableWidget 和我的类 MainWindow?

python - Django,关于 zip 文件响应的问题

c++ - 元编程中最后递归的问题