programing

무한 재귀 오류 없이 __getattribute__를 구현하려면 어떻게 해야 합니까?

megabox 2023. 8. 17. 21:06
반응형

무한 재귀 오류 없이 __getattribute__를 구현하려면 어떻게 해야 합니까?

클래스의 한 변수에 대한 액세스를 재정의하고 다른 변수는 모두 정상적으로 반환합니다.이 작업을 수행하려면 어떻게 해야 합니까?__getattribute__?

다음을 시도했지만(내가 하려는 작업도 표시되어야 함) 재귀 오류가 발생합니다.

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return self.__dict__[name]

>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp

액세스 시도로 인해 재귀 오류가 발생합니다.self.__dict__내속성 안의 __getattribute__합니다.__getattribute__한 번. 한시약만. 에번다를 하면 됩니다.object__getattribute__은 작동합니다: 신합니, 작동다.

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return object.__getattribute__(self, name)

이는 다음과 같은 이유로 작동합니다.object(이 예에서는)가 기본 클래스입니다. 버전인 버을전호출니다합본기의▁the▁version▁of▁base다▁by▁calling니호출합.__getattribute__당신은 당신이 전에 있었던 반복적인 지옥을 피합니다.

ipython 출력과 foo의 코드.py:

In [1]: from foo import *

In [2]: d = D()

In [3]: d.test
Out[3]: 0.0

In [4]: d.test2
Out[4]: 21

업데이트:

현재 설명서의 새 스타일 클래스에 대한 추가 특성 액세스 섹션에는 무한 재귀를 방지하기 위해 이 작업을 수행할 것을 권장하는 내용이 있습니다.

사실, 저는 당신이 대신 특별한 방법을 사용하고 싶어한다고 생각합니다.

Python 문서의 인용:

__getattr__( self, name)

특성 조회가 일반적인 위치에서 특성을 찾지 못한 경우(즉, 인스턴스 특성이 아니거나 자체 클래스 트리에서 찾을 수 없는 경우) 호출됩니다.name특성 이름입니다.는 (하거나 ( 속성 값을 .AttributeError예외.
로 만약 이 일반적인 통해 된다면, 만약속성이일메통발면다된견해을즘,__getattr__()사이의 (의) 의도적입니다.__getattr__()그리고.__setattr__()도 그렇고 그렇지 에도 그렇습니다.) 이 작 효 모 이 수 두 행 됩 니 로 다 유 외 의 업 그 율 은 성 과 ▁. 니 됩 수 다 행 ▁this 모 두 ▁. ▁otherwise ) ▁both ▁done) ▁is__setattr__()인스턴스의 다른 특성에 액세스할 수 없습니다.적어도 인스턴스 변수의 경우 인스턴스 속성 사전에 값을 삽입하지 않고 대신 다른 개체에 값을 삽입하여 전체 컨트롤을 위장할 수 있습니다. 내용은 다음을 하십시오.__getattribute__()새로운 스타일 클래스에서 전체 제어를 실제로 얻는 방법은 아래의 방법입니다.

참고: 이 기능이 작동하려면 인스턴스에 다음이 없어야 합니다.test줄 성, 그서선self.test=20제거해야 합니다.

파이썬 언어 참조:

메서드에서 동일한 . 를 들어, 이 드 메 에 서 동 항 이 로 메 호 필 속 액 야 합 니 해 다 스 세 에 성 한 요 여 를 하 드 클 서 서 출 기 무스래본한상재귀름방위현구일지으해한하은를기▁in ,▁methodutes▁class ▁with▁its▁always ▁attrib ▁for 다▁it니합▁base▁any▁theobject.__getattribute__(self, name).

의미:

def __getattribute__(self,name):
    ...
        return self.__dict__[name]

당신은 다음과 같은 속성을 요구하고 있습니다.__dict__그것은 속성이기 때문에__getattribute__를 검색하기 위해 호출됩니다.__dict__어느 쪽인가 하면__getattribute__그 말을...야다야다야다

return  object.__getattribute__(self, name)

기본 클래스 사용__getattribute__실제 속성을 찾는 데 도움이 됩니다.

어때요?__getattribute__사용된 방법은?

일반 점선 조회 전에 호출됩니다.상승하면,AttributeError그 다음에 우리는 전화합니다.__getattr__.

이 방법을 사용하는 경우는 거의 없습니다.표준 라이브러리에는 두 가지 정의만 있습니다.

$ grep -Erl  "def __getattribute__\(self" cpython/Lib | grep -v "/test/"
cpython/Lib/_threading_local.py
cpython/Lib/importlib/util.py

모범 사례

단일 속성에 대한 액세스를 프로그래밍 방식으로 제어하는 올바른 방법은 .Class입니다.D(명백한 의도된 동작을 복제하기 위해 선택적으로 세터 및 삭제자와 함께) 다음과 같이 작성해야 합니다.

class D(object):
    def __init__(self):
        self.test2=21

    @property
    def test(self):
        return 0.

    @test.setter
    def test(self, value):
        '''dummy function to avoid AttributeError on setting property'''

    @test.deleter
    def test(self):
        '''dummy function to avoid AttributeError on deleting property'''

사용 방법:

>>> o = D()
>>> o.test
0.0
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0

속성은 데이터 설명자이므로 일반 점선 조회 알고리즘에서 가장 먼저 찾는 항목입니다.

옵션:__getattribute__

를 통해 모든 속성에 대한 조회를 구현해야 하는 경우 몇 가지 옵션을 사용할 수 있습니다.

  • 올리다AttributeError,발생시키는__getattr__호출됨(실행되는 경우)
  • 까지 그것으로부터 무엇인가를 돌려주다.
    • 부모를 호출하는 데 사용(계속)object) 행실
    • __getattr__
    • 어떻게든 당신만의 점선 조회 알고리즘을 구현하는 것.

예:

class NoisyAttributes(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self, name):
        print('getting: ' + name)
        try:
            return super(NoisyAttributes, self).__getattribute__(name)
        except AttributeError:
            print('oh no, AttributeError caught and reraising')
            raise
    def __getattr__(self, name):
        """Called if __getattribute__ raises AttributeError"""
        return 'close but no ' + name    


>>> n = NoisyAttributes()
>>> nfoo = n.foo
getting: foo
oh no, AttributeError caught and reraising
>>> nfoo
'close but no foo'
>>> n.test
getting: test
20

당신이 원래 원했던 것.

다음 예에서는 원래 원하는 작업을 수행하는 방법을 보여 줍니다.

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return super(D, self).__getattribute__(name)

그리고 다음과 같이 행동할 것입니다.

>>> o = D()
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
>>> del o.test

Traceback (most recent call last):
  File "<pyshell#216>", line 1, in <module>
    del o.test
AttributeError: test

코드 검토

코드에 주석이 있습니다.당신은 자신에 대한 점박이 룩업을 하고 있습니다.__getattribute__이것이 재귀 오류가 발생하는 이유입니다.이름이 다음인지 확인할 수 있습니다."__dict__" 및사를 합니다.super문제를 해결하기 위해, 하지만 그것은 적용되지 않습니다.__slots__저는 그것을 독자들에게 연습으로 남겨두겠습니다.

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:      #   v--- Dotted lookup on self in __getattribute__
            return self.__dict__[name]

>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp

하시겠습니까?__getattribute__당신은 실제로 무엇을 성취하기 위해 노력하고 있습니까?

요청한 작업을 수행하는 가장 쉬운 방법은 다음과 같습니다.

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    test = 0

또는:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    @property
    def test(self):
        return 0

" " " " " " 는 " " " 입니다.D이 다 수 있 니 습 다 를test각각의 경우에첫 번째 경우d.test될 이고, 두 번째는 020 것고이, 일는번 0 이 될 입니다.그 이유는 당신에게 맡기겠습니다.

이기 때문에 예제 2가 실패하고 Edit2: Greg가 2번째로 읽기 전용이기 이라고 지적했습니다.__init__메서드가 20으로 설정하려고 했습니다.이에 대한 보다 완벽한 예는 다음과 같습니다.

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    _test = 0

    def get_test(self):
        return self._test

    def set_test(self, value):
        self._test = value

    test = property(get_test, set_test)

분명히, 수업으로서 이것은 거의 완전히 쓸모가 없지만, 여러분에게 다음 단계로 넘어갈 수 있는 아이디어를 줍니다.

보다 안정적인 버전은 다음과 같습니다.

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21
    def __getattribute__(self, name):
        if name == 'test':
            return 0.
        else:
            return super(D, self).__getattribute__(name)

부모 클래스에서 __getattribute__ 메서드를 호출하여 결국 개체로 돌아갑니다.다른 조상들이 재정의하지 않는 경우 __속성 가져오기__ 메서드.

언급URL : https://stackoverflow.com/questions/371753/how-do-i-implement-getattribute-without-an-infinite-recursion-error

반응형