기본 동작을 중단하지 않고 파이썬에서 __getattr__을 어떻게 재정의합니까?


185

__getattr__멋진 것을하기 위해 클래스 의 메소드 를 재정의하고 싶지만 기본 동작을 중단하고 싶지 않습니다.

이 작업을 수행하는 올바른 방법은 무엇입니까?


20
"변경"이 아니라 "파산"입니다. "팬시"속성은 내장 속성을 방해하지 않아야하며 가능한 한 많이 동작해야합니다. 마이클의 대답은 정확하고 도움이됩니다.
olooney

답변:


268

재정의 __getattr__는 좋을 __getattr__것입니다. 인스턴스에 이름과 일치하는 속성이없는 경우에만 최후의 수단으로 호출됩니다. 당신이 액세스하는 경우 예를 들어 foo.bar, 다음 __getattr__경우에만 호출 될 것이다 foo라는 어떤 속성이 없습니다 bar. 처리하지 않으려는 속성 인 경우 다음을 발생시킵니다 AttributeError.

class Foo(object):
    def __getattr__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            raise AttributeError

그러나, 달리 __getattr__, __getattribute__(해당 상속 객체들을, 즉 새로운 스타일의 클래스에 대한 작업)를 먼저 호출됩니다. 이 경우 다음과 같이 기본 동작을 유지할 수 있습니다.

class Foo(object):
    def __getattribute__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            return object.__getattribute__(self, name)

자세한 내용 은 Python 문서를 참조하십시오 .


바, 당신의 편집은 내가 대답에서 보여준 것과 같은 +1입니다.

12
쿨, 파이썬은 슈퍼 인을 부르는 것을 좋아하지 않는 것 같습니다 __getattr__. ( AttributeError: 'super' object has no attribute '__getattr__')
gatoatigrado 2016 년

1
코드를 보지 않으면 알기가 어렵지만 getattr을 정의하는 수퍼 클래스가없는 것 같습니다 .
Colin vH

"이것은 getattr (object, name)을 호출하고 예외가 발생하는지 여부를 확인함으로써 구현됩니다." docs.python.org/2/library/functions.html#hasattr
ShaBANG

1
-1이는 않습니다 기본 동작을 수정합니다. 이제 AttributeError예외 args에 속성 컨텍스트가 없습니다.
wim

34
class A(object):
    def __init__(self):
        self.a = 42

    def __getattr__(self, attr):
        if attr in ["b", "c"]:
            return 42
        raise AttributeError("%r object has no attribute %r" %
                             (self.__class__.__name__, attr))

>>> a = A()
>>> a.a
42
>>> a.b
42
>>> a.missing
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in __getattr__
AttributeError: 'A' object has no attribute 'missing'
>>> hasattr(a, "b")
True
>>> hasattr(a, "missing")
False

고마워 소스에서 파지 않고 기본 메시지가 올바른지 확인하고 싶었습니다.
ShawnFumo

4
클래스가 재정의되는 경우 self.__class__.__name__대신에 사용해야 한다고 생각합니다.self.__class____repr__
Michael Scott Cuthbert

3
이것은 허용되는 답변보다 낫지 만, 코드를 다시 작성하지 않아도되고 문구가 수정되거나 향후 예외 개체에 추가 컨텍스트가 추가되는 경우 업스트림 변경 사항을 놓칠 수 있습니다.
wim

13

Michael 답변을 확장하려면을 사용하여 기본 동작을 유지하려면 __getattr__다음과 같이하십시오.

class Foo(object):
    def __getattr__(self, name):
        if name == 'something':
            return 42

        # Default behaviour
        return self.__getattribute__(name)

이제 예외 메시지가 더 설명 적입니다.

>>> foo.something
42
>>> foo.error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __getattr__
AttributeError: 'Foo' object has no attribute 'error'

2
@ fed.pavlo 확실합니까? 아마 당신은 혼합 __getattr__하고 __getattribute__?
José Luis

내 잘못이야. 나는 자기 자신과 다른 방법으로 전화를 놓쳤다. ; (
fed.pavlo

2
실제로 @ 마이클의 대답은이 대답하지 않고 불완전
Grijesh 차우
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.