在运行时创建类时,使用`exec`而不是`type()`有什么好处?

时间:2011-10-06 15:48:28

标签: python namedtuple dynamic-class-creation

我想在python中在运行时动态创建类。

例如,我想复制下面的代码:

>>> class RefObj(object):
...     def __init__(self, ParentClassName):
...         print "Created RefObj with ties to %s" % ParentClassName
... class Foo1(object):
...     ref_obj = RefObj("Foo1")
... class Foo2(object):
...     ref_obj = RefObj("Foo2")
... 
Created RefObj with ties to Foo1
Created RefObj with ties to Foo2
>>>

...但我希望动态创建Foo1,Foo2,Foo类(即:在执行期间而不是在第一次编译时)。

实现这一目标的一种方法是使用type(),如下所示:

>>> class RefObj(object):
...     def __init__(self, ParentClassName):
...         print "Created RefObj with ties to %s" % ParentClassName
... def make_foo_class(index):
...     name = "Foo%s" % index
...     return type(name, (object, ), dict(ref_obj = RefObj(name)))
... 
>>> Foo1 = make_foo_class(1)
Created RefObj with ties to Foo1
>>> Foo2 = make_foo_class(2)
Created RefObj with ties to Foo2
>>> type(Foo1()), type(Foo2())
(<class 'Foo1'>, <class 'Foo2'>)

我也可以使用exec来实现它,就像这样:

>>> class RefObj(object):
...     def __init__(self, ParentClassName):
...         print "Created RefObj with ties to %s" % ParentClassName
... def make_foo_object(index):
...     class_template = """class Foo%(index)d(object):
...         ref_obj = RefObj("Foo%(index)d")
...         """ % dict(index = index)
...     global RefObj
...     namespace = dict(RefObj = RefObj)
...     exec class_template in namespace
...     return namespace["Foo%d" % index]
... 
>>> Foo1 = make_foo_object(1)
Created RefObj with ties to Foo1
>>> Foo2 = make_foo_object(2)
Created RefObj with ties to Foo2
>>> type(Foo1()), type(Foo2())
(<class 'Foo1'>, <class 'Foo2'>)

使用exec并不适合我(因为我预计很多人都不会阅读此问题),但exec 正好 python的collections.namedtuple()is implemented如何(见this line)。同样非常相关的是由班级的创造者(Raymond Hettinger)对exec here的使用进行辩护。在这种辩护中,声明“它是命名元组的一个关键特性,它们完全等同于手写类”,人们可能会暗示使用{{1 }}不如使用type() ...

那么好

有区别吗?为什么要使用exec vs exec

我希望答案可能是两种方式都是相同的,只是type()实现有很多通过它来编写的命名元组变量,并且通过为所有方法动态生成闭包来实现这一点变得笨拙,但我想知道是否还有更多东西。

关于我对namedtuple的不适,我确实认识到,如果不信任方无法向其中注入恶意代码,那应该没问题......只是确保这让我感到紧张。

3 个答案:

答案 0 :(得分:7)

我建议type超过exec

实际上,class语句只是调用type的语法糖:类主体在其自己的命名空间内执行,然后传递给元类,默认为{ {1}}如果未指定自定义元类。

这种方法不那么错误,因为不需要在运行时解析代码,甚至可能更快一些。

答案 1 :(得分:4)

为什么不在函数中创建一个类?

def foo_factory(index):
    name = 'Foo%d' % index

    class Foo(object):
        ref_obj = RefObj(name)

    Foo.__name__ = name
    return Foo

答案 2 :(得分:2)

在exec上使用type()没有任何缺点。我认为雷蒙德的防守有点防守。您必须选择最易读且易懂的技术。两种方式都会造成令人困惑的代码。

你应该尽量避免首先避免创建类的代码,这是最好的。