[python] __getattr__과 __getattribute__의 차이점 이해

나는 사이의 차이를 이해하려고 __getattr__하고 __getattribute__, 그러나, 나는 그것을 실패하고있다.

대답 스택 오버플로 질문에 차이 __getattr__대는__getattribute__ 말합니다 :

__getattribute__객체의 실제 속성을보기 전에 호출되므로 올바르게 구현하기가 까다로울 수 있습니다. 무한 재귀로 매우 쉽게 끝날 수 있습니다.

나는 그것이 무엇을 의미하는지 전혀 모른다.

그런 다음 계속 말합니다.

당신은 거의 확실하게 원합니다 __getattr__.

왜?

나는 경우 읽었 __getattribute__실패 __getattr__라고합니다. 그렇다면 왜 같은 일을하는 두 가지 방법이 있습니까? 내 코드가 새로운 스타일 클래스를 구현하는 경우 무엇을 사용해야합니까?

이 질문을 해결하기 위해 몇 가지 코드 예제를 찾고 있습니다. Google은 최선을 다해 최선을 다했지만 찾은 답변으로 문제에 대해 자세히 논의하지는 않습니다.

문서가 있으면 읽을 준비가되었습니다.



답변

먼저 몇 가지 기본 사항.

객체를 사용하면 해당 속성을 처리해야합니다. 보통 우리는 그렇습니다 instance.attribute. 때로는 더 많은 제어가 필요합니다 (사전 속성의 이름을 모르는 경우).

예를 들어, instance.attribute될 것입니다 getattr(instance, attribute_name). 이 모델을 사용하면 attribute_name을 제공하여 속성을 얻을 수 있습니다 을 문자열로 을 .

사용 __getattr__

또한 클래스를 통해 명시 적으로 관리하지 않는 속성을 처리하는 방법을 __getattr__메소드 를 통해 지정할 수 있습니다 .

파이썬은 아직 정의되지 않은 속성을 요청할 때마다이 메소드를 호출하므로 그와 관련된 작업을 정의 할 수 있습니다.

전형적인 사용 사례 :

class A(dict):
    def __getattr__(self, name):
       return self[name]
a = A()
# Now a.somekey will give a['somekey']

주의 사항 및 사용 __getattribute__

당신은 모든 속성을 잡을해야하는 경우 에 관계없이 존재 여부 , 사용 __getattribute__대신. 차이점은 __getattr__실제로 존재하지 않는 속성 만 호출한다는 것입니다. 속성을 직접 설정 한 경우 해당 속성을 참조하면을 호출하지 않고 속성을 검색합니다 __getattr__.

__getattribute__ 항상 호출됩니다.


답변

__getattribute__ 속성 액세스가 발생할 때마다 호출됩니다.

class Foo(object):
    def __init__(self, a):
        self.a = 1

    def __getattribute__(self, attr):
        try:
            return self.__dict__[attr]
        except KeyError:
            return 'default'
f = Foo(1)
f.a

이로 인해 무한 재귀가 발생합니다. 여기서 범인은 선 return self.__dict__[attr]입니다. 모든 속성이 self.__dict__이름으로 저장 되고 사용 가능한 것으로 가장합니다 (진실에 가깝습니다) . 라인

f.a

a속성에 액세스하려고합니다 f. 이 호출합니다 f.__getattribute__('a'). __getattribute__그런 다음로드를 시도합니다 self.__dict__. __dict__의 속성 self == f이므로 파이썬 호출 은 속성에 f.__getattribute__('__dict__')다시 액세스하려고합니다 '__dict__. 이것은 무한 재귀입니다.

__getattr__대신에 사용 되었다면

  1. 때문에 실행이없는 것이 결코 f있다a속성 입니다.
  2. 실행했다면 (당신이 요청했다고 가정 해보십시오 f.b) __dict__이미 거기에 있기 때문에 찾기 위해 호출되지 않았 으며 속성을 찾는 다른 모든 방법이 실패한__getattr__ 경우에만 호출됩니다 .

위의 클래스를 사용하여 ‘올바른’방법 __getattribute__

class Foo(object):
    # Same __init__

    def __getattribute__(self, attr):
        return super(Foo, self).__getattribute__(attr)

super(Foo, self).__getattribute__(attr)__getattribute__‘가장 가까운’수퍼 클래스의 메소드 (공식적으로 클래스의 메소드 분석 순서 (MRO)의 다음 클래스)를 현재 오브젝트에 바인딩 합니다.self 후 호출하여 작업을 수행 할 수 있도록합니다.

이 문제는 __getattr__파이썬 속성을 찾을 수 없을 때까지 정상적인 일 을 할 수있게 함으로써 피할 수 있습니다 . 그 시점에서 파이썬 손은 __getattr__메소드 를 제어 하고 무언가를 생각해냅니다.

또한을 사용하여 무한 재귀에 빠질 수 있다는 점도 주목할 가치가 있습니다 __getattr__.

class Foo(object):
    def __getattr__(self, attr):
        return self.attr

나는 그것을 운동으로 남겨 두겠습니다.


답변

나는 다른 답변의 차이 설명하는 훌륭한 일했을 생각 __getattr____getattribute__, 그러나 당신이 사용하고자하는 이유를 명확하지 않을 수 있습니다 한 가지입니다 __getattribute__. 멋진 점은 __getattribute__클래스에 액세스 할 때 본질적으로 점에 과부하를 허용한다는 것입니다. 이를 통해 낮은 수준에서 속성에 액세스하는 방법을 사용자 정의 할 수 있습니다. 예를 들어, 자체 인수 만 취하는 모든 메소드가 특성으로 처리되는 클래스를 정의한다고 가정하십시오.

# prop.py
import inspect

class PropClass(object):
    def __getattribute__(self, attr):
        val = super(PropClass, self).__getattribute__(attr)
        if callable(val):
            argcount = len(inspect.getargspec(val).args)
            # Account for self
            if argcount == 1:
                return val()
            else:
                return val
        else:
            return val

그리고 대화식 통역사에서 :

>>> import prop
>>> class A(prop.PropClass):
...     def f(self):
...             return 1
...
>>> a = A()
>>> a.f
1

물론 이것은 어리석은 예이며 아마도 이것을하고 싶지 않을 수도 있지만 재정의에서 얻을 수있는 힘을 보여줍니다 __getattribute__.


답변

나는 다른 사람의 훌륭한 설명을 겪었습니다. 그러나이 블로그 Python Magic Methods 및__getattr__ 에서 간단한 답변을 찾았습니다 . 다음은 모두 거기에 있습니다.

__getattr__매직 메소드를 사용하여 존재하지 않는 속성 조회를 가로 채서 실패하지 않는 것을 수행 할 수 있습니다.

class Dummy(object):

    def __getattr__(self, attr):
        return attr.upper()

d = Dummy()
d.does_not_exist # 'DOES_NOT_EXIST'
d.what_about_this_one  # 'WHAT_ABOUT_THIS_ONE'

그러나 속성이 존재하면 __getattr__호출되지 않습니다.

class Dummy(object):

    def __getattr__(self, attr):
        return attr.upper()

d = Dummy()
d.value = "Python"
print(d.value)  # "Python"

__getattribute__유사하다 __getattr__중요한 차이, __getattribute__차단합니다 EVERY 속성이 존재하거나하지 않을 경우 속성 조회는 중요하지 않습니다.

class Dummy(object):

    def __getattribute__(self, attr):
        return 'YOU SEE ME?'

d = Dummy()
d.value = "Python"
print(d.value)  # "YOU SEE ME?"

이 예에서 d객체에는 이미 속성 값이 있습니다. 그러나 액세스하려고하면 원래 예상 값 ( “Python”)을 얻지 못합니다. 우리는 무엇이든 __getattribute__돌려받는 것입니다. 그것은 우리가 사실상 value 속성을 잃었 음을 의미합니다. 도달 할 수 없게되었습니다.


답변