【发布时间】:2011-10-07 00:35:52
【问题描述】:
我想在运行时在 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 的@ 987654336@ 类is implemented(见this line)。同样非常相关的是类的创建者(Raymond Hettinger)对exechere的这种使用的辩护。在这个辩护中,声明“命名元组的一个关键特征是它们完全等同于手写类”,这可能意味着使用type()还不如用exec...
有区别吗?为什么使用exec 与type()?
我希望答案可能是两种方式都是相同的,只是 namedtuple 实现有很多 namedtuple 变量贯穿其中,并且通过为所有方法动态生成闭包来执行此操作使代码变得笨拙,但我想知道这是否还有其他内容。
关于我对exec 的不适,我确实认识到,如果不受信任的各方无法向其中注入恶意代码,那应该没问题...只是确保这让我感到紧张。
【问题讨论】:
-
blog.ccpgames.com/kristjan/2011/05/28/namedtuple-and-exec 也有关于这个问题的一些很好的讨论,还有另一篇关于它的好博客文章我现在看不到。您没有说明
type在您的情况下存在问题的任何原因,所以我不知道您为什么要打扰exec,因为您知道type有效。 (显然除了好奇心)。 -
@agf - 很棒的链接,谢谢!我最初对
type没有意见,因为这两种方法都有效。我只是对这些差异感到好奇,并试图了解在namedtuple中使用exec的原因。提供的类/函数签名参数非常好,但是...我经常遇到需要使用 decorator 包的装饰器问题。 -
您能否给出需要动态类创建背后的原因,还是只是出于好奇?
-
从模板生成代码是一种基本而强大的技术。 ANTLR 和模板语言等工具利用这种技术取得了良好的效果。 namedtuple 的早期版本使用 type 而不是 exec 但这种方法不能很好地扩展——它很难维护,有点不可读,有奇怪的错误,而且不是自我记录。经过一些清理,exec 版本最终变得有些漂亮:hg.python.org/cpython/file/3.2/Lib/collections.py#l235 我承认 exec 让一些开发人员感到恶心,但这是一个心理问题,而不是技术性的。
标签: python namedtuple dynamic-class-creation