2011-10-06 1 views
10

파이썬에서 런타임에 클래스를 동적으로 만들고 싶습니다.런타임에 클래스를 생성 할 때`type()`보다`exec`를 사용하면 어떤 이점이 있습니까?

예를 들어, 나는 아래의 코드를 복제 할 :

>>> 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, 푸 클래스, 즉 (동적으로 생성 할 : 실행 중에 대신 첫 번째 패스 엮다). 이를 달성하기

한 가지 방법과 같이, 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정확히 파이썬의 클래스 is implemented (this line 참조). 또한이 계열의 개발자 (Raymond Hettinger)가 exechere을 사용하는 것을 방어해야합니다. 이 방어에서는 "은 명명 된 튜플의 핵심 기능으로 손으로 작성한 클래스과 정확히 동일합니다. type()의 사용이 exec만큼 좋지 않음을 나타낼 수 있습니다. ...

차이가 있습니까? 왜 exectype() 대 사용해야합니까?

나는 대답은 두 가지가 동일한 지있을 수 있습니다 예상과는 namedtuple 구현은 그것을 통해 후추를 namedtuple 변수를 많이 가지고 단순히 모든 방법은 코드를 다루기 얻을 제작을 위해 함께이 일을하는 것은 동적으로 클로저를 생성 ,하지만 더 많은 것을 알고 싶습니다.

불편한 점은 exec입니다. 신뢰할 수없는 당사자가 악의적 인 코드를 삽입하는 방법이 없다면 신경 써야합니다.

+1

http://blog.ccpgames.com/kristjan/2011/05/28/namedtuple-and-exec/에서도이 문제에 대해 좋은 토론이 진행되었으며 이에 대한 또 다른 좋은 블로그 게시물이있었습니다. 나는 지금 보지 않는다. 상황에서'type'이 문제가되는 이유를 제시하지 않았으므로'type'이 작동한다는 것을 알고 있기 때문에 왜'exec '에 신경 쓰는지 모르겠습니다. (호기심을 제외하고는 분명히). – agf

+0

@agf - 좋은 링크, 고마워! 두 가지 접근법이 모두 작동하기 때문에 처음에는'type'에 문제가 없었습니다. 차이점에 대해서 궁금해서'namedtuple'에서'exec' 사용 이유를 이해하려고했습니다. 하지만 클래스/함수 시그니처 인수는 훌륭합니다. 필자는 종종 [decorator] (http://pypi.python.org/pypi/decorator) 패키지를 사용해야하는 데코레이터 문제가 있습니다. – Russ

+0

역동적 인 클래스 생성에 대한 필요성을 뒷받침 할 수 있습니까? 아니면 단지 호기심입니까? – dhill

답변

2

exec()보다 type()을 사용하는 데에는 단점이 없습니다. 나는 레이몬드의 수비가 약간 방어 적이라고 생각한다. 가장 이해하기 쉬운 기술을 선택해야합니다. 두 가지 방법 모두 혼동스러운 코드를 만듭니다.

클래스를 생성하는 코드를 피하기 위해 최선을 다해야합니다.

+0

@agfL 죄송합니다. 귀하가 무슨 말씀을 하시는지 잘 모르겠습니다. –

+3

'decorator' 라이브러리를위한'exec'의 인자 중 하나는 장식 된 함수/메소드의 서명을 보존하는 것이 더 쉽다는 것입니다. 나는 또한'named'라는 이름의 인자라고 생각합니다.'exec'를 사용하면 손으로 코딩했을 때와 똑같은 클래스가 만들어졌지만,'type'으로는 클래스가 다르다는 것입니다. – agf

+0

나는 비행 중에 클래스를 생성하는 것을 피하고 싶지만, 클래스 생성 전에 범위 내에 있도록 보장 할 수없는 매개 변수를 기반으로 클래스 속성을 만들어야하는 경우가 있습니다. 동적 클래스는 현재 가장 단순한 방법처럼 보입니다. – Russ

4

왜 함수에 클래스를 만들지 않으십니까?

def foo_factory(index): 
    name = 'Foo%d' % index 

    class Foo(object): 
     ref_obj = RefObj(name) 

    Foo.__name__ = name 
    return Foo 
+0

실제로'Foo'에 대해 _dynamic_ 뭔가가있을 때마다 매번 같은 방식으로 생성하고 싶지는 않습니다. – agf

+0

물론 이것은 단지 해골 일뿐입니다. – yak

+0

이런 식으로'namedtuple' 또는 시그니처 보존 데코레이터를 구현하는 방법을 보여주십시오. 그것이 "결코 유연하지 않습니다"라고 말하는 것은 사실이 아닙니다. – agf

7

나는 여기 보다 exec을 권장합니다. 사실

class 문은 type를 호출 단지 문법 설탕입니다 : 클래스 본문은 다음에는 사용자 정의 메타 클래스는 type 기본값으로 지정되지 않은 경우 메타 클래스에 전달됩니다 자신의 네임 스페이스 내에서 실행됩니다.

이 접근법은 런타임에 코드를 구문 분석 할 필요가 없으므로 오류가 덜 발생하며 조금 더 빨라질 수도 있습니다.

+0

실용성을 위해 +1. -1의 가치가 없습니다. – agf

관련 문제