Я хочу динамически создавать классы во время выполнения в 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
- это точно , как collections.namedtuple()
класс Python реализован (см. эту строку ).Также очень важна защита этого использования exec
здесь , создателем класса (Раймондом Хеттингером).В этой защите утверждается, что « Для именованных кортежей ключевым признаком является то, что они в точности эквивалентны рукописному классу », что может означать, что использование type()
не так хорошо, как использование exec
...
Есть ли разница?Зачем использовать exec
против type()
?
Я ожидаю, что ответ может заключаться в том, что оба пути одинаковы, и просто в реализации namedtuple
есть много переменных namedtuple, перенесенных через негои выполнение этого с динамически генерирующими замыканиями для всех методов сделало код громоздким, но я хочу знать, есть ли что-то еще в этом.
Что касается моего дискомфорта с exec
, я признаю, что если естьдля ненадежных сторон нет способа внедрить в него гнусный код, это должно быть хорошо ... это только то, что заставляет меня нервничать.