무한 재귀 오류 없이 __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▁the
object.__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
'programing' 카테고리의 다른 글
Excel VBA - 열거된 요소의 값 설정 (0) | 2023.08.22 |
---|---|
Swift에서 사용자 상호 작용을 비활성화하는 방법UI 보기? (0) | 2023.08.22 |
Excel VBA에 개체 필요 오류가 있습니다. (0) | 2023.08.17 |
오류 2002(HY000):소켓 '/var/run/mysqld/mysqld/mysqld를 통해 로컬 MySQL 서버에 연결할 수 없습니다.sock' (2) 해결책이 작동하지 않음 (0) | 2023.08.17 |
병합 커밋이 없는 Git 로그 보기 (0) | 2023.08.17 |