В чем преимущество использования `exec` перед` type () `при создании классов во время выполнения?

Я хочу динамически создавать классы во время выполнения в 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())
(, )

Я также могу добиться этого с помощью 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())
(, )

Использование exec мне не нравится (как я ожидаю, что не многим людям, читающим этот вопрос), но exec точно как python collections. namedtuple () класс реализован (см. в этой строке ). Также очень актуальна защита этого использования exec здесь создателем класса (Раймондом Хеттингером).В этой защите утверждается, что « Ключевой особенностью именованных кортежей является то, что они в точности эквивалентны написанному от руки классу », что может означать, что использование типа () не так хорошо, как использование exec ...

Есть ли разница? Зачем использовать exec vs type () ?

Я ожидаю, что ответ может заключаться в том, что оба способа одинаковы, и просто реализация namedtuple имеет через него пропитано множество переменных namedtuple, и выполнение этого с динамической генерацией замыканий для всех методов сделало код громоздким, но я хочу знать, есть ли в этом что-то еще.

Что касается моего дискомфорта с exec , я признаю, что если у ненадежных сторон нет никакого способа внедрить в него гнусный код, все должно быть в порядке ... это просто гарантия того, что я нервный.

10
задан Russ 6 October 2011 в 15:48
поделиться