Rus*_*uss 10 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
>>>
Run Code Online (Sandbox Code Playgroud)
...但我希望动态创建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'>)
Run Code Online (Sandbox Code Playgroud)
我也可以这样实现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'>)
Run Code Online (Sandbox Code Playgroud)
采用exec不跟我坐好(因为我希望它不会有很多人谁读了这个问题),但exec就是究竟如何Python的collections.namedtuple()类中实现(见本线).同样非常相关的是由这个类的创造者(Raymond Hettinger)来保护exec 这里的使用.在这种辩护中,声明" 命名元组的一个关键特性是它们完全等同于手写类 ",人们可能会暗示使用type()它不如使用exec......
有区别吗?为何使用execvs type()?
我希望答案可能是两种方式都是相同的,只是namedtuple实现中有很多名称变量通过它来实现,并且通过动态生成所有方法的闭包来实现这一点使得代码变得笨拙,但我想知道如果还有更多的东西.
关于我的不适exec,我确实认识到,如果没有任何方法让不信任的人注入邪恶的代码,它应该没问题......这只是确保这让我感到紧张.
我会type在exec这里推荐.
实际上,该class语句只是对于调用的语法糖type:类主体在其自己的命名空间内执行,然后将其传递给元类,type如果未指定自定义元类,则默认为该类.
这种方法不那么错误,因为不需要在运行时解析代码,甚至可能更快一些.
使用 type() 相对于 exec 没有任何缺点。我认为雷蒙德的防守有点防守。您必须选择您认为最可读和最容易理解的技术。这两种方法都会产生令人困惑的代码。
您应该非常努力地避免首先创建类的代码,那是最好的。