2014-03-24 2 views
9

질문은 을 말합니다. 기술적 인 배경이 아니라을 사용 사례로 사용하는 것이 좋습니다.속성 대 설명자 대 __getattribute__ 사용 사례

파이썬에서, 당신은 재산하는 설명, 또는 마술 방법를 통해 속성의 액세스를 제어 할 수 있습니다. 어느 것이 유스 케이스에서 가장 파이썬 이냐? 그들 모두는 같은 효과를 가지는 것 같습니다 (아래 예 참조). 기술자

  • ...의 경우에 사용되어야한다 :

    • 재산권가 :

      내가 좋아하는 대답을 찾고 있어요 ...의 경우 대신 속성으로 사용되어야한다.

    • 매직 방법 : 다음 경우에만 사용하십시오.

    유스 케이스 개체가 아직 데이터베이스에 존재하지 않기 때문에 예를 들어, __init__ 방법에 설정하지 못할 수 있습니다 속성을 것

    예,하지만 나중에에서 시각. 속성에 액세스 할 때마다 설정되고 반환되어야합니다.

    복사 & Python 셸에 붙여 넣기와 함께 작동하는 예제로서 두 번째로 요청할 때만 속성을 표시하려는 클래스가 있습니다. 그래서, 어느 것이 가장 좋은 방법입니까, 아니면 다른 상황이 있습니까? 그 중 하나가 더 낫습니다. 여기를 구현하는 세 가지 방법은 다음과 같습니다

    재산권으로 ::

    class ContactBook(object): 
        intents = 0 
    
        def __init__(self): 
         self.__first_person = None 
    
        def get_first_person(self): 
         ContactBook.intents += 1 
         if self.__first_person is None: 
          if ContactBook.intents > 1: 
           value = 'Mr. First' 
           self.__first_person = value 
          else: 
           return None 
         return self.__first_person 
    
        def set_first_person(self, value): 
         self.__first_person = value 
    
        first_person = property(get_first_person, set_first_person) 
    

    __getattribute__으로 ::

    class ContactBook(object): 
        intents = 0 
    
        def __init__(self): 
         self.first_person = None 
    
        def __getattribute__(self, name): 
         if name == 'first_person' \ 
           and object.__getattribute__(self, name) is None: 
          ContactBook.intents += 1 
          if ContactBook.intents > 1: 
           value = 'Mr. First' 
           self.first_person = value 
          else: 
           value = None 
         else: 
          value = object.__getattribute__(self, name) 
         return value 
    

    기술자는 ::

    class FirstPerson(object): 
        def __init__(self, value=None): 
         self.value = None 
    
        def __get__(self, instance, owner): 
         if self.value is None: 
          ContactBook.intents += 1 
          if ContactBook.intents > 1: 
           self.value = 'Mr. First' 
          else: 
           return None 
         return self.value 
    
    
    class ContactBook(object): 
        intents = 0 
        first_person = FirstPerson() 
    

    EAC 시간 그 중 하나가이 동작 ::

    book = ContactBook() 
    print(book.first_person) 
    # >>None 
    print(book.first_person) 
    # >>Mr. First 
    
  • +1

    '__getattribute__'은 ** 항상 ** 호출되며, 다른 수단을 통해 속성이 발견되지 않으면'__getattr__' 만 호출됩니다. '__getattribute__'는'property' (및 다른 디스크립터 객체)가 작업을 수행하는 메커니즘입니다. –

    +0

    그건 _descriptor_ 아니 _decorator_ – Eric

    +0

    @ 에릭 : 감사합니다, 나는 질문을 편집했습니다. – Iodnas

    답변

    11

    기본적으로 가능한 가장 간단한 것을 사용하십시오. 대충 말하자면, 복잡성/중대성의 순서는 다음과 같습니다 : 일반 속성, property, __getattr__, __getattribute__/설명자. (__getattribute__ 및 사용자 정의 설명은 아마 매우 자주 할 필요가 없습니다 두 가지입니다.)이 엄지 손가락의 몇 가지 간단한 규칙에 이르게 : 일반 속성이 작동하는지

    • property를 사용하지 마십시오.
    • property이 작동하면 고유 한 설명자를 쓰지 마십시오.
    • property이 작동하면 __getattr__을 사용하지 마십시오.
    • __getattr__이 작동하는 경우 __getattribute__을 사용하지 마십시오.

    좀 더 구체적으로 말하면 속성 하나 또는 작은 속성 집합을 처리하기 위해 속성을 사용하십시오. __getattr__을 사용하여 모든 속성의 처리 또는 작은 세트를 제외한 모든 처리를 사용자 정의하십시오. __getattr__을 사용하기를 원한다면 __getattribute__을 사용하십시오. 매우 복잡한 작업을하는 경우 자신의 설명자 클래스를 작성하십시오.

    가져 오기/설정을 후크하려는 속성 집합이 하나 이상있는 경우 property을 사용합니다. 즉, obj.propobj.prop = 2과 같은 것들을 사용자가 작성한 함수를 몰래 호출하여 상황을 사용자 정의합니다.

    많은 개별 속성을 실제로 정의하지 않고 전체 속성 액세스 프로세스 전체를 사용자 정의하고자하는 많은 속성에 대해이 작업을 수행하려면 __getattr__을 사용하십시오. 즉, obj.prop1obj.prop2 등을 연결하는 대신 많은 수의 사용자가 obj.<anything>에 연결하여 일반적으로 처리 할 수 ​​있기를 원합니다.

    그러나 실제로는 존재하는 속성에 대해 어떤 일이 발생할지 재정의 할 수는 없으며 그렇지 않으면 AttributeError를 발생시키는 속성 사용에 대한 담요 처리로 연결될 수 있습니다. __getattribute__을 사용하면 모두을 처리 할 수 ​​있습니다. __getattribute__으로 엉망이 아닌 정상적인 속성까지도 처리 할 수 ​​있습니다. 따라서 __getattribute__을 사용하면 상당히 기본적인 동작을 중단시킬 가능성이 있으므로 __getattr__을 사용하는 것으로 간주하고 충분하지 않은 경우에만 사용해야합니다. 또한 성능에 상당한 영향을 줄 수 있습니다. 예를 들어, 일부 속성을 정의하는 클래스를 래핑하는 경우 __getattribute__을 사용해야 할 수도 있습니다. 이러한 속성을 사용자 정의 방식으로 래핑하여 일부 상황에서는 정상적으로 작동하지만 다른 속성에서는 사용자 정의 비헤이비어를 얻을 수 있기를 원합니다. 상황.

    마지막으로 독자적인 설명자를 작성하는 것은 상당히 진보 된 작업입니다. property은 설명자이며, 아마도 95 %의 경우에 필요한 유일한 것입니다.자신 만의 디스크립터를 작성하는 이유에 대한 간단한 예제는 here으로 주어진다 : 기본적으로 유사한 행동으로 여러개의 property을 써야한다면 그렇게 할 수있다. 설명자를 사용하면 코드 반복을 피하기 위해 일반적인 동작을 제외시킬 수 있습니다. 커스텀 디스크립터는 Django 나 SQLAlchemy와 같은 시스템을 구동하는데 사용된다. 당신이 그 복잡한 수준에서 무언가를 쓰는 것을 발견한다면 커스텀 서술자를 작성해야 할 수도 있습니다.

    예제에서 property이 최선의 선택입니다. 안에 if name == 'somespecificname'을 수행하는 경우 대개 항상 (항상은 아님) 빨간색 플래그입니다. 특정 이름 만 특별히 처리해야하는 경우 __getattribute__ 수준까지 오르지 않고 수행 할 수 있습니다. 마찬가지로 __get__에 대한 모든 내용을 속성의 getter 메서드로 작성할 수있는 경우 사용자 지정 설명자를 작성하는 것은 의미가 없습니다.

    +1

    '__getattribute__' 재정의를 사용하기 전에 디스크립터 객체를 잘 사용할 수 있습니다. 나는 거의 **'__getattribute__' 훅을 사용해야합니다. :-) –

    +0

    어쩌면, 그렇습니다. 제 생각에'__getattribute__'와 디스크립터는 둘 다 드물기 때문에 어느 것이 먼저 복잡하다고 말할 수있을만큼 어렵지는 않습니다. – BrenBarn

    +1

    필자는 기술자를 자주 사용했습니다. 속성으로 액세스 할 때 클래스에 정의 된 객체가 인스턴스에 바인딩되도록하는 것이 좋은 기능입니다. –

    2

    __getattribute__property (다른 설명)을 가능하게하는 후크 첫 번째 장소에서 작업을 가지고 있으며, 에 대한 개체의 모든 속성 액세스라고합니다. 속성이나 사용자 정의 설명자가 사용자의 요구에 충분하지 않은 경우 하위 API로 간주하십시오. __getattr__은 대체 수단으로 다른 수단을 통해 속성을 찾지 못한 경우 __getattribute__에 의해 호출됩니다.

    더 동적 인 속성 (예 : 알고리즘 방식으로 값에 매핑되는 일련의 속성)에 대해 고정 된 이름의 동적 속성에는 __getattr__을 사용하십시오.

    설명자는 인스턴스에 임의의 개체을 바인딩해야합니다. 메소드 객체를 예를 들어 좀 더 발전된 것으로 대체해야 할 때; 최근 예제는 메서드 개체에 대한 추가 특성 및 메서드를 지원하는 데 필요한 class-based decorator wrapping methods입니다. 일반적으로 스칼라 속성으로 생각할 때 설명자를 필요로하지 않습니다.