我想在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
的不适,我确实认识到,如果不信任方无法向其中注入恶意代码,那应该没问题......只是确保这让我感到紧张。
答案 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()没有任何缺点。我认为雷蒙德的防守有点防守。您必须选择最易读且易懂的技术。两种方式都会造成令人困惑的代码。
你应该尽量避免首先避免创建类的代码,这是最好的。