Quiero crear dinámicamente clases en tiempo de ejecución en python.¿Cuál es la ventaja de usar `exec` sobre` type() `al crear clases en tiempo de ejecución?
Por ejemplo, yo desea replicar el código de abajo:
>>> 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
>>>
... pero quiero las clases foo1, Foo2, Foo a ser creados dinámicamente (es decir: durante la ejecución en lugar de en la primera pasada compilar).
Una forma de lograr esto es con type()
, así:
>>> 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'>)
también puedo lograrlo con exec
, así:
>>> 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'>)
El uso de exec
no se sienta bien conmigo (como espero que no con mucha gente que lea esta pregunta) pero exec
es exactamente cómo python collections.namedtuple()
clase is implemented (ver this line). También es muy relevante la defensa de este uso de exec
here, por el creador de la clase (Raymond Hettinger). En esta defensa, se afirma que "es una característica clave para las tuplas con nombre que son exactamente equivalentes a una clase manuscrita", lo que podría implicar que el uso de type()
no es tan bueno como el uso de exec
...
¿Hay alguna diferencia? ¿Por qué usar exec
contra type()
?
espero que la respuesta puede ser que ambas formas son lo mismo y es simplemente que la aplicación namedtuple
tiene una gran cantidad de variables namedtuple salpicados a través de él, y haciendo esto con generar dinámicamente el cierre de todos los métodos hicieron el código de obtener difícil de manejar , pero quiero saber si hay algo más en esto.
En cuanto a mi incomodidad con exec
, reconozco que si no hay forma en que las partes no confiables le inyecten un código nefasto, debería estar bien ... es solo asegurarse de que eso me ponga nervioso.
También hay un poco de buena discusión sobre el tema en http://blog.ccpgames.com/kristjan/2011/05/28/namedtuple-and-exec/, y había otra buena publicación en el blog al respecto No veo ahora. No has presentado ninguna razón por la cual 'type' sea problemático en tu situación, así que no sé por qué te molestarías con' exec' porque sabes que 'type' funciona. (Aparte de la curiosidad obviamente). – agf
@agf - gran enlace, gracias! Originalmente no tuve un problema con 'type', ya que ambos enfoques funcionan. Tenía curiosidad por las diferencias e intentaba entender el motivo del uso de 'exec' en' namedtuple'. Sin embargo, los argumentos de firma de clase/función presentados son excelentes ... Frecuentemente tengo problemas de decorador que requieren el uso del paquete [decorator] (http://pypi.python.org/pypi/decorator). – Russ
¿Podría darnos la razón detrás de la necesidad de creación dinámica de clases o es solo curiosidad? – dhill