2016-11-07 10 views
0

나는 Descriptor HowTo Guide에 기술자에 대해 읽어 봤는데, 나는이 문장에 의해 혼란 스러워요 : 인스턴스의 사전 데이터 기술자와 같은 이름을 가진 항목이있는 경우파이썬 속성과 설명

의 데이터 디스크립터가 우선한다.

사전에 동일한 이름의 두 항목 (일반 항목과 데이터 설명자)을 어떻게 포함 할 수 있습니까? 또는 설명자 인 속성이 __dict__에 저장되어 있지 않습니까? 인스턴스가 예를 네임 스페이스 (그래서 instance.__dict__)에서의 삶을 속성 동안

답변

3

데이터 기술자는 클래스 네임 스페이스에 살고있다. 이것들은 2 개의 별도의 사전들입니다. 그래서 여기서 충돌이 없습니다.

그래서 인스턴스 bar에 이름 foo에 대한 특정 속성 조회에, 파이썬은 다음 순서로, (아래 C 이름 type(bar)) 그것의 클래스에 보이는 :

  1. C.foo가 조회됩니다. 데이터 설명자 인 경우 조회가 종료됩니다. C.foo.__get__(bar, C)이 리턴됩니다. 그렇지 않으면, 파이썬은 3 단계에서이 결과를 저장할 것입니다.

  2. C.foo이 존재하지 않거나 일반 속성 인 경우 Python은 bar.__dict__['foo']을 찾습니다. 존재하는 경우 반환됩니다. C.foo이 데이터 설명자 인 경우이 부분에 도달하지 않습니다.

  3. bar.__dict__['foo']이없고 C.foo이있는 경우 C.foo이 사용됩니다. C.foo이 (데이터가 아닌) 설명자 인 경우 C.foo.__get__(bar, C)이 반환됩니다.

(C.foo 정말 C.__dict__['foo']이지만, 단순 위해 내가 위의 클래스에 기술자 액세스를 무시 한 것을 참고).

아마도 구체적인 예가 도움이 될 것입니다. 여기에 두 가지 설명이있다, 하나는 데이터 기술자 (A __set__ 방법이가)이고, 다른 하나는 하지 데이터 설명 :

>>> class DataDesc(object): 
...  def __get__(self, inst, type_): 
...   print('Accessed the data descriptor') 
...   return 'datadesc value' 
...  def __set__(self, inst, value): 
...   pass # just here to make this a data descriptor 
... 
>>> class OtherDesc(object): 
...  def __get__(self, inst, type_): 
...   print('Accessed the other, non-data descriptor') 
...   return 'otherdesc value' 
... 
>>> class C(object): 
...  def __init__(self): 
...   # set two instance attributes, direct access to not 
...   # trigger descriptors 
...   self.__dict__.update({ 
...    'datadesc': 'instance value for datadesc', 
...    'otherdesc': 'instance value for otherdesc', 
...   }) 
...  datadesc = DataDesc() 
...  otherdesc = OtherDesc() 
... 
>>> bar = C() 
>>> bar.otherdesc # non-data descriptor, the instance wins 
'instance value for otherdesc' 
>>> bar.datadesc # data descriptor, the descriptor wins 
Accessed the data descriptor 
'datadesc value' 
+0

데이터 설명자가 클래스 사전에 있습니다. "Descriptor HowTo Guide"는 인스턴스 사전이 클래스 사전 이전에 검색되도록 제안하는 것 같습니다 : "예를 들어, ax는 .__ dict __ [ 'x']로 시작하는 검색 체인을 가지고 있습니다. 그런 다음 (a) .__ dict __ [ 'x'], 그리고 메타 클래스를 제외한 유형 (a)의 기본 클래스를 계속 진행하십시오. " –

+0

@SirVisto는 거기에서 단순화하고 있습니다. 그림에서 데이터 설명자를 가져온 경우 순서가 완벽합니다.그 시점에서 데이터 서술자를 도입하면 이야기가 불필요하게 복잡해집니다. –

+0

사실,이 기사에서는 나중에 설명합니다. "구현은 인스턴스 변수보다 데이터 설명자를 우선시하고 비 데이터 기술자보다 우선 순위가 높은 인스턴스 변수를 제공하고 제공된 경우 __getattr __()에 우선 순위를 최하위로 할당하는 선행 체인을 통해 작동합니다." –

1

이 코드 다음 고려 :이 코드

class X: 
    @property 
    def x(self): 
     return 2 

x1 = X() 
x1.__dict__['x'] = 1 
print(x1.x) 

데이터 설명자 (클래스에 정의 됨)가 인스턴스 사전보다 우선하기 때문에 2를 인쇄합니다.

+0

이것에 대한 근거는 무엇입니까? 나는 직관적으로 같은 이름의 클래스 속성을 섀도 잉하기 위해 인스턴스 속성을 기대할 것이다 ... –

+0

@SirVisto : 이것은 데이터 디스크립터가 접근을 완벽하게 제어 할 수 있도록한다 (그래서 설정 및 삭제 포함). 인스턴스가 사전에 있다면, 'del inst.foo'는 때때로 인스턴스에 도달하고, 때로는 데이터 서술자에 도달합니다. 설정을 위해서'inst.foo = 'value ''를 할 때 일어날 일은 인스턴스 속성이 이미 있다면 중요할까요? 그런 다음 누가 설정을 처리 할 책임이 있습니까? 일관되게 * 항상 * 데이터 설명자를 책임있게 작성하면 모든 질문을 명확하고 일관되게 해결할 수 있습니다. –

+0

@SirVisto : 또 다른 동기는 인스턴스에서 실수로 일부 클래스 속성을 재정의 할 수 없도록하는 기능입니다. 예를 들어 '__class__' 속성은 인스턴스에 설정되어서는 안됩니다. 그러면 해당 클래스를 더 이상 찾을 수 없으므로'__class__ '은 클래스의 데이터 설명 자입니다. –