从动态创建的基础列表创建类

时间:2018-04-20 19:23:13

标签: python

有没有办法从动态基类列表中创建一个类?

def dynamic_class_creator(base, base2):
    class Derived(base, base2):
        pass
    return Derived

class Mixin1(object):
    def greet(self):
        print ("Howdy!")

class Mixin1a(object):
    def insult(self):
        print ("You have a lot to learn.")

class Mixin2(object):
    def insult(self):
        print ("Idiot!")

polite = dynamic_class_creator(Mixin1, Mixin1a)()
polite.greet()
polite.insult()

complex = dynamic_class_creator(Mixin1, Mixin2)()
complex.greet()
complex.insult()

这可以按预期工作:

Howdy!                    
You have a lot to learn.  
Howdy!                    
Idiot!

但我无法弄清楚如何从任意长度的列表中分配这些基数:

def dynamic_class_creator(*bases):
    class Derived(*bases):
        pass
    return Derived
(...)

给出:

  File "../test2.py", line 4
    class Derived(*bases):  
                  ^         
SyntaxError: invalid syntax 

修改

一个建议的解决方案:

def dynamic_class_creator(*bases):
    class Derived(bases):
        pass
    return Derived
(...)

给出:

Traceback (most recent call last):
  File "../test2.py", line 20, in <module>
    polite = dynamic_class_creator(Mixin1, Mixin1a)()
  File "../test2.py", line 4, in dynamic_class_creator
    class Derived(bases):
TypeError: Error when calling the metaclass bases
    tuple() takes at most 1 argument (3 given)

2 个答案:

答案 0 :(得分:3)

您可以使用type()构造函数的三参数形式。引用the documentation,“使用三个参数,返回一个新的类型对象。这实际上是class语句的动态形式。

# TESTED with Python3
def dynamic_class_creator(*bases):
    return type('Derived', bases, {})

上述问题是您丢失了class语法。例如,这使得向Derived添加方法很困难。

您可以保留类声明的漂亮语法,仍然使用metaclass修改对type()的调用。

以下是一个完整的示例,演示了metaclass=type()以及常规和混合基类的使用。

# TESTED with Python3
def dynamic_class_creator(*mixins):
    def metaclass(name, bases, members):
        return type(name, bases + mixins, members)

    class Derived(BaseClass, metaclass=metaclass):
        def praise(self):
            print("Good job!")

    return Derived

class BaseClass(object):
    def goodbye(self):
        print("Goodbye!")

class Mixin1(object):
    def greet(self):
        print("Howdy!")

class Mixin1a(object):
    def insult(self):
        print("You have a lot to learn.")

class Mixin2(object):
    def insult(self):
        print("Idiot!")

polite = dynamic_class_creator(Mixin1, Mixin1a)()
polite.greet()
polite.insult()
polite.praise()
polite.goodbye()

complex = dynamic_class_creator(Mixin1, Mixin2)()
complex.greet()
complex.insult()

您可以将任意关键字传递给元类函数。考虑这个例子:

# TESTED with Python3
def mixin_metaclass(name, bases, members, mixins):
    return type(name, bases+mixins, members)

def dynamic_class_creator(*mixins):
    class Derived(metaclass=mixin_metaclass, mixins=mixins):
        pass
    return Derived

最后,请注意,所有上述示例都是使用Python3进行测试的。这是一个Python2版本:

# TESTED with Python2
def dynamic_class_creator(*mixins):
    def metaclass(name, bases, members):
        return type(name, mixins+bases, members)
    class Derived(object):
        __metaclass__ = metaclass
        def praise(self):
            print("Good job!")
    return Derived

答案 1 :(得分:0)

为了完整起见,如果你已经在使用另一个元类(就像我一样),这里有一个基于Robᵩ的解决方案:

Python 3

def mixin_metaclass(name, bases, members, mixins, super_meta=type):
    return super_meta(name, bases + mixins, members)

def dynamic_class_creator(*mixins):
    class Derived(metaclass=mixin_metaclass, mixins=mixins, super_meta=MyMeta):
        pass
    return Derived

Python 2

def mixin_meta(super_meta, *mixins):
    def _meta(name, bases, members):
        return super_meta(name, mixins + bases, members)
    return _meta

def dynamic_class_creator(*mixins):
    class Derived(object):
        __metaclass__ = mixin_meta(MyMeta, *mixins)
    return Derived