Я хочу динамически создавать классы во время выполнения в 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
, я признаю, что если у ненадежных сторон нет никакого способа внедрить в него гнусный код, все должно быть в порядке ... это просто гарантия того, что я нервный.