2010-08-14 2 views
15

오늘 나는 파이썬 here에서 놀라운 메타 클래스 정의를 보았고, 메타 클래스 정의는 효과적으로 인라인되었다. 관련 부분은Python에서 메타 클래스 정의를 인라인 할 때?

class Plugin(object): 
    class __metaclass__(type): 
     def __init__(cls, name, bases, dict): 
      type.__init__(name, bases, dict) 
      registry.append((name, cls)) 

언제 그런 인라인 정의를 사용하는 것이 합리적입니까?

또한 인수 :

인수 한 가지 방법은 생성 된 메타 클래스는이 기술을 사용하여 다른 곳에서 재사용이되지 않는다는 것입니다. 반론은 메타 클래스를 사용하는 일반적인 패턴이 메타 클래스를 정의하고 그것을 한 클래스에서 사용하고 그런 다음 그것을 상속한다는 것입니다. 예를 들어, a conservative metaclass에 정의

class DeclarativeMeta(type): 
    def __new__(meta, class_name, bases, new_attrs): 
     cls = type.__new__(meta, class_name, bases, new_attrs) 
     cls.__classinit__.im_func(cls, new_attrs) 
     return cls 
class Declarative(object): 
    __metaclass__ = DeclarativeMeta 
    def __classinit__(cls, new_attrs): pass 

class Declarative(object): #code not tested! 
    class __metaclass__(type): 
     def __new__(meta, class_name, bases, new_attrs): 
      cls = type.__new__(meta, class_name, bases, new_attrs) 
      cls.__classinit__.im_func(cls, new_attrs) 
      return cls 
    def __classinit__(cls, new_attrs): pass 

다른 고려 사항으로 작성되었습니다 수 있을까?

답변

19

다른 모든 형태의 중첩 된 클래스 정의와 마찬가지로 중첩 된 메타 클래스는 많은 종류의 "프로덕션 용도"에 대해 ("상속에 의한 경우를 제외하고 해당 메타 클래스를 다시 사용하지 않아도 괜찮 으면" 디버깅이나 인트로 스펙 션에서는 다소 불편할 수 있습니다.

기본적으로, 당신은 모듈에 정의 된 모든 사용자 정의 메타 클래스 무엇을 인 (자신의 __module____name__ 속성에 따라 서로 undistiguishable 것을 끝낼거야 대신 메타 클래스에게 적절한 최상위 이름을주는 파이썬은 필요하다면 그들의 repr을 형성하기 위해 사용한다.) 고려 :

>>> class Mcl(type): pass 
... 
>>> class A: __metaclass__ = Mcl 
... 
>>> class B: 
... class __metaclass__(type): pass 
... 
>>> type(A) 
<class '__main__.Mcl'> 
>>> type(B) 
<class '__main__.__metaclass__'> 

IOW을, 당신은 (메타 클래스는, 클래스의 유형 기억) "클래스 A 인 유형"검사 할 경우, 당신은 명확하고 유용한 답변을 얻을 - 그것은 주요 모듈 Mcl입니다. 그것은 이는 main 모듈 __metaclass__을 말한다, 그러나 그것은 심지어 사실이 아니다 : 당신이 "클래스 B 인 유형"검사 할 경우, 대답은 모두 유용하지 않습니다

>>> import __main__ 
>>> __main__.__metaclass__ 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'module' object has no attribute '__metaclass__' 
>>> 

... 거기 그런 것이, 실제로이다; 그 repr은 오해하기 쉽고별로 도움이되지 않습니다 ;-).

클래스의 repr은 본질적으로 간단하고 유용하며 일관된 규칙이지만 대부분의 경우 class 문이 모듈 범위에서 고유하지 않거나 전혀 모듈 범위에 있지 않습니다 (오히려 함수 또는 클래스 본문 내에서) 또는 존재하지 않아도 (클래스는 물론 class 문을 사용하지 않고 명시 적으로 메타 클래스를 호출하여 빌드 할 수 있습니다.)이 방법은 다소 오해의 소지가 있습니다 (가능한 한 최대 해결책은 피하는 것입니다. , 그 특별한 경우는, 그것을 사용함으로써 실질적인 이점을 얻을 수있는 경우를 제외하고).

이 같은 범위에서 두 class
>>> class A(object): 
... def foo(self): print('first') 
... 
>>> x = A() 
>>> class A(object): 
... def foo(self): print('second') 
... 
>>> y = A() 
>>> x.foo() 
first 
>>> y.foo() 
second 
>>> x.__class__ 
<class '__main__.A'> 
>>> y.__class__ 
<class '__main__.A'> 
>>> x.__class__ is y.__class__ 
False 

가, 두 번째는 이름 (여기서, A)를 리 바인드하지만, 기존 인스턴스 이름으로, 객체에 의해 이름의 첫 바인딩을하지 참조 : 예를 들어, 고려 - 두 클래스 객체가 남아 있으므로 인스턴스의 type (또는 __class__ 속성)을 통해서만 액세스 할 수있는 객체가있는 경우 (해당 객체가없는 경우 첫 번째 객체가 사라짐) 두 클래스가 동일한 이름과 모듈을 가지므로 같은 표현). 그러나 그들은 뚜렷한 대상이다. 클래스 또는 함수 본문에 중첩 된 클래스 또는 직접 (디버그 또는 내성 검사가 호출 될 경우) 비슷한 혼란을 일으킬 수있는 메타 클래스 (type 포함)를 호출하여 생성 된 클래스.

따라서 코드를 디버그하거나 다른 방법으로 내성 할 필요가없는 경우 메타 크라스를 중첩하는 것은 괜찮습니다. 누구든지이 단점을 이해한다면 누구나 함께 살 수 있습니다 (비록 멋진 코드를 사용하는 것만 큼 편리하지는 않지만). , 실제 이름은 - lambda으로 코드화 된 함수를 디버깅하는 것과 마찬가지로 def으로 코딩 된 디버깅과 같이 편리하지 않을 수 있습니다. lambdadef의 유추를 통해 익명의 "중첩 된"정의는 완전히 단순한 메타 캐어 (no brainer)처럼 디버깅이나 인트로 스펙 션이 요구되지 않는다고 합리적으로 주장 할 수 있습니다.

파이썬 3에서는 "중첩 된 정의"가 작동하지 않습니다. class A(metaclass=Mcl):에서와 같이 메타 클래스가 키워드 인수로 전달되어야하므로 본문에 __metaclass__을 정의해도 아무런 효과가 없습니다. 파이썬 2 코드에서 중첩 된 메타 클래스 정의는 아마도 코드가 파이썬 3으로 포팅 될 필요가 없다는 것을 알고있는 경우에만 적합 할 것이라고 생각한다. (당신이이 포트를 훨씬 더 어렵게 만들고 있기 때문에 다시 말해, Python 3의 일부 버전이 속도, 기능 또는 제 3 자의 거대하고 강렬한 이점을 얻는 몇 년 안에는 존재하지 않을 "쓰레기"코드 인 목적을위한 메타 클래스 정의를 해제합니다. 파이썬 2.7 (파이썬 2의 마지막 버전)을 통한 파티 지원. 컴퓨팅의 역사는 우리에게 보여줍니다 당신이,가 버리는 것으로 예상

코드, "완전히 당신을 놀라게하고, 아마도 코드가 같은시기에 썼다 (약 20 년 후 여전히 존재의 사랑스러운 버릇이있다 나이를위한 "은 완전히 잊어 버렸습니다 ;-). 이것은 확실히 메타 클래스의 중첩 된 정의를 피할 것을 제안하는 것처럼 보일 것입니다.

+1

아주 좋은 설명, 고마워. – cji

+0

인상적인 대답. "당신은 의존하겠습니까?"와 직렬화에 약간 빠져 있습니다. –

+0

'pickle'이 얼마나 많은지 잘 모르겠습니다. 산 세척은 잘 작동하는 것으로 보인다 [here] (http://gist.github.com/524744). –

관련 문제