10

我想在运行时在 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并不适合我(正如我所期望的那样,很多阅读此问题的人都不会使用),但这正是execpython类的实现方式(参见这一行)。同样非常相关的是类的创建者(Raymond Hettinger)对here的这种使用的辩护。在这个辩护中,声明“命名元组的一个关键特征是它们完全等同于手写类”,这可能意味着使用不如使用...collections.namedtuple()exec type()exec

有区别吗?为什么使用execvs type()

我希望答案可能是两种方式都是相同的,只是namedtuple实现中有很多 namedtuple 变量贯穿其中,并且通过为所有方法动态生成闭包来执行此操作会使代码变得笨拙,但我想知道如果还有更多的东西。

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

4

3 回答 3

7

我会推荐type这里exec

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

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

于 2011-10-06T16:18:59.173 回答
4

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

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

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

    Foo.__name__ = name
    return Foo
于 2011-10-06T16:06:23.693 回答
2

使用 type() 而不是 exec 没有缺点。我认为雷蒙德的防守有点防守。您必须选择您认为最易读和易于理解的技术。两种方式都会产生令人困惑的代码。

您应该非常努力地避免首先创建类的代码,那将是最好的。

于 2011-10-06T16:10:39.743 回答