我希望能在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()
类实现的方法(见此行),非常相关的还有该类的创作者Raymond Hettinger在这里对使用exec
进行的辩护。在这篇辩护文章中,他说:“命名元组的一个关键特性就是它们与手写类完全相同”,这可能意味着使用type()
并不如使用exec
好...
有什么区别吗? 为什么要使用exec
而不是type()
?
我想答案可能是两种方法是一样的,只是namedtuple
实现有很多命名元组变量,用动态生成闭包来生成所有方法让代码变得难以操作,但我想知道是否还有其他原因。关于我对
exec
的不适感,我确实意识到如果没有任何方式让不受信任的方注入恶意代码,那么使用它应该是安全的...只是要确保这一点让我感到紧张。
type
存在问题,因为两种方法都可以工作。我只是对差异感到好奇,并试图理解namedtuple
中使用exec
的原因。然而,提供的类/函数签名参数非常棒... 我经常遇到装饰器问题,需要使用 decorator 包。 - Russ