나는 사이의 차이를 이해하려고 __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__
대신에 사용 되었다면
- 때문에 실행이없는 것이 결코
f
있다a
속성 입니다. - 실행했다면 (당신이 요청했다고 가정 해보십시오
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 속성을 잃었 음을 의미합니다. 도달 할 수 없게되었습니다.