问题
I want to dynamically create classes at runtime in python.
For example, I want to replicate the code below:
>>> 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
>>>
... but I want the Foo1, Foo2, Foo classes to be created dynamically (ie: during execution instead of on first-pass compile).
One way to achieve this is with type(), like so:
>>> 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'>)
I can also achieve it with exec, like so:
>>> 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'>)
The use of exec
doesn't sit well with me (as I expect it doesn't with a lot of people who read this question) but exec
is exactly how python's collections.namedtuple()
class is implemented (see this line). Also very relevant is the defense of this use of exec
here, by the creator of the class (Raymond Hettinger). In this defense, it is stated that "It is a key feature for named tuples that they are exactly equivalent to a hand-written class", which one might take to imply that the use of type()
is not as good as using exec
...
Is there a difference? Why use exec
vs type()
?
I expect the answer may be that both ways are the same and it is simply that the namedtuple
implementation has a lot of namedtuple variables peppered through it, and doing this with dynamically generate closures for all methods made the code get unwieldy, but I want to know if there is something more to this.
Regarding my discomfort with exec
, I do recognize that if there is no way whatsoever for untrusted parties to inject nefarious code into it, it should be fine... it is just ensuring that that makes me nervous.
回答1:
There is no disadvantage to using type() over exec. I think Raymond's defense is a bit defensive. You have to choose the technique that you find most readable and understandable. Both ways create confusing code.
You should try really hard to avoid code that creates classes in the first place, that would be best.
回答2:
I would recommend type
over exec
here.
In fact, the class
statement is just syntactic sugar for a call to type
: The class body is executed within its own namespace, which is then passed on to the metaclass, which defaults to type
if no custom metaclass is specified.
This approach is less errorprone since there is no need to parse code at runtime, and might even be a bit faster.
回答3:
Why not just create a class in a function?
def foo_factory(index):
name = 'Foo%d' % index
class Foo(object):
ref_obj = RefObj(name)
Foo.__name__ = name
return Foo
来源:https://stackoverflow.com/questions/7676947/what-is-the-advantage-in-using-exec-over-type-when-creating-classes-at-run