Chcę dynamicznie tworzyć klasy w czasie wykonywania w Pythonie.Jaka jest korzyść z używania `exec` ponad` type() `podczas tworzenia klas w środowisku wykonawczym?
Na przykład, chcę replikować poniższy kod:
>>> 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
>>>
... ale chcę klasy foo1, foo2, Foo być tworzone dynamicznie (tj: w trakcie realizacji, a nie na pierwszym-pass skompilować).
Jednym ze sposobów osiągnięcia tego celu jest z type()
, tak:
>>> 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'>)
Mogę również osiągnąć go exec
, tak:
>>> 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'>)
Zastosowanie exec
nie współgra ze mną (jak się spodziewam, nie z wieloma ludźmi, którzy czytają to pytanie), ale exec
jest dokładnie jak python's collections.namedtuple()
klasa is implemented (patrz this line). Bardzo istotna jest również obrona tego użycia przez autora klasy (Raymonda Hettingera). W tej obronie jest powiedziane, że "Jest to kluczowa cecha dla nazwanych krotek, które są dokładnie równoważne z ręcznie pisaną klasą", co może oznaczać, że użycie type()
nie jest tak dobre, jak użycie exec
...
Czy jest jakaś różnica? Dlaczego warto korzystać z exec
kontra type()
?
Spodziewam się, że odpowiedź może być tak, że obie strony są takie same i jest to po prostu, że realizacja namedtuple
ma wiele zmiennych namedtuple pieprzem przez niego, i robi to z dynamicznego generowania zamknięć dla wszystkich metod wykonany kod dostać nieporęczny , ale chcę wiedzieć, czy jest w tym coś więcej.
Odnośnie mojego dyskomfortu z exec
, zdaję sobie sprawę, że jeśli nie ma sposobu, aby niezaufane strony wprowadziły do niego nikczemny kod, powinno być dobrze ... to tylko upewnia mnie, że denerwuję się.
Istnieje również dobra dyskusja na ten temat na stronie http://blog.ccpgames.com/kristjan/2011/05/28/namedtuple-and-exec/ oraz pojawił się kolejny dobry wpis na blogu na ten temat. Nie widzę teraz. Nie przedstawiłeś żadnego powodu, dla którego 'typ' jest problematyczny w twojej sytuacji, więc nie wiem, dlaczego zawracałeś sobie głowę' exec', ponieważ wiesz, że 'type' działa. (Inne niż oczywiście ciekawość). – agf
@agf - świetny link, dzięki! Początkowo nie miałem problemu z 'type', ponieważ oba podejścia działają. Byłem po prostu ciekawy różnic i próbowałem zrozumieć powód używania 'exec' w' namedtuple'. Przedstawione argumenty sygnatur klasy/funkcji są znakomite, chociaż ... Często mam problemy z dekoratorem, które wymagają użycia pakietu [dekorator] (http://pypi.python.org/pypi/decorator). – Russ
Czy możesz podać powód potrzeby dynamicznego tworzenia klasy, czy jest to tylko ciekawość? – dhill