2017-10-19 2 views
1

나는 __prepare__ 함수에 대해 가르칩니다. 그리고 PEP3115메타 클래스 및 __prepare__()

# The custom dictionary 
class member_table(dict): 
    def __init__(self): 
     self.member_names = [] 

    def __setitem__(self, key, value): 
     # if the key is not already defined, add to the 
     # list of keys. 
     if key not in self: 
      self.member_names.append(key) 

     # Call superclass 
     dict.__setitem__(self, key, value) 

# The metaclass 
class OrderedClass(type): 

    # The prepare function 
    @classmethod 
    def __prepare__(metacls, name, bases): # No keywords in this case 
     return member_table() 

    # The metaclass invocation 
    def __new__(cls, name, bases, classdict): 
     # Note that we replace the classdict with a regular 
     # dict before passing it to the superclass, so that we 
     # don't continue to record member names after the class 
     # has been created. 
     result = type.__new__(cls, name, bases, dict(classdict)) 
     result.member_names = classdict.member_names 
     return result 

class MyClass(metaclass=OrderedClass): 
    # method1 goes in array element 0 
    def method1(self): 
     pass 

    # method2 goes in array element 1 
    def method2(self): 
     pass 

내 질문에이 조각이 줄에 있습니다 참조 : result.member_names = classdict.member_names

어떻게 변수가 member_table 클래스의 속성을 얻을 classdict 수 있을까? __prepare__ 함수는 member_table의 인스턴스를 반환하지만, member_table()classdict.member_names 사이의 링크는 어떻게 생성되는 걸까요?

여러분 모두에게 감사드립니다.

답변

2

정확히 준비가되어 있으므로 매우 간단합니다.

3.3.3.3. 클래스 네임 스페이스 준비 적절한 메타 클래스가 확인되면 클래스 네임 스페이스가 준비됩니다. 메타 클래스에 __prepare__ 특성이있는 경우 namespace = metaclass.__prepare__(name, bases, **kwds) (추가로 키워드 인수가 클래스 정의에서 오는 경우)이라고합니다.

메타 클래스에 __prepare__ 속성이없는 경우 클래스는 빈 순서 맵핑으로 초기화됩니다.

수단

https://docs.python.org/3/reference/datamodel.html#preparing-the-class-namespace

, 메타 클래스 __new____init__ 방법으로 전달되는 속성 classdict 정확히 __prepare__ 반환하는 동일한 목적으로한다.

해당 개체는 매핑 인스턴스 여야합니다. 즉, dict처럼 작동하고 적어도 __setitem__ 메서드를 가진 개체 여야합니다. 이 __setitem__ 메소드는 선언 된 클래스 본문 자체 내에 설정된 모든 변수에 대해 Python에 의해 호출됩니다.

즉, 일반 클래스의 경우 사용자 지정 메타 클래스가 없으면 변수는 사전 (Python 3.6의 사전 순 목록)에 기록됩니다.

파이썬이 클래스 본문 내에서 각 문을 실행함에 따라 이런 일이 발생합니다. 이 기능을 처음 설계 할 때

In [21]: class M(type): 
    ...:  def __prepare__(self, *args): 
    ...:   class CustomDict(dict): 
    ...:    __repr__ = lambda self: "I am a custom dict: " + str(id(self)) 
    ...:   namespace = CustomDict() 
    ...:   print("From __prepare__", namespace) 
    ...:   return namespace 
    ...: 
    ...:  def __new__(metacls, name, bases, namespace): 
    ...:   print("From __new__:", namespace) 
    ...:   return super().__new__(metacls, name, bases, namespace) 
    ...:  
    ...:  

In [22]: class Test(metaclass=M): 
    ...:  def __init__(self): 
    ...:   ... 
    ...:  print("From class body:", locals(), locals()["__init__"]) 
    ...:  
    ...:  
From __prepare__ I am a custom dict: 140560887720440 
From class body: I am a custom dict: 140560887720440 <function Test.__init__ at 0x7fd6e1bd7158> 
From __new__: I am a custom dict: 140560887720440 

주요 사용 사례 아마 정확히 의미있는 클래스 본문 내부에 선언의 순서를 만들기의 가능성 :이 하나의 클래스 본체 내부에 locals()를 호출해야합니다 반환 된 동일한 개체가 . 즉, __prepare__ 메서드는 collections.OrderedDict 인스턴스를 반환 할 수 있으며 __new__ 또는 __init__이 해당 순서대로 작동합니다. 파이썬 3.6부터는 클래스 속성의 순서가 기본적으로 지정되어 있으며, 기능이 너무 발전되어 여전히 용도에 대해 생각 해봐야합니다.

+0

답변 해 주셔서 감사합니다. 하나 더 작은 질문 -'__prepare__' 함수가 항상 dict 또는 장식 된 dict 유형 (다른 유형이 아님) 인 네임 스페이스를 반환하는지 확인할 수 있습니까? – luoshao23

+0

"확인"이란 무엇을 의미합니까? '__prepare__'를 저작하고 그것이 무엇을 반환 하는지를 알아야합니다. 완전한 매핑 객체처럼 행동 할 필요가 없다면,'__setitem__' 만 필요하고, mclass'__init__'의 코드는 어떻게 처리해야 하는지를 알고 있어야합니다. – jsbueno

+0

(질문에 대한 답변을 얻은 경우, 대답을 수락하는 것을 잊지 마십시오) – jsbueno

관련 문제