[python] __getattr__과 __getattribute__의 차이점

__getattr__또는 사용시기를 이해하려고합니다 __getattribute__. 언급 된 문서__getattribute__새로운 스타일의 클래스에 적용됩니다. 새로운 스타일의 수업은 무엇입니까?



답변

사이의 키 차이 __getattr__와는 __getattribute____getattr__속성이 일반적인 방법을 찾을 수 없습니다 경우에만 호출됩니다. 누락 된 속성에 대한 폴백을 구현하는 데 유용하며 원하는 두 가지 중 하나 일 수 있습니다.

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

새로운 스타일 클래스는 object, 구식 클래스에서 파생되며 명시 적 기본 클래스가없는 Python 2.x의 클래스입니다. 그러나 이전 스타일과 새로운 스타일의 클래스의 차이는 사이의 선택 중요한 것이 아니다 __getattr____getattribute__.

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


답변

마술 방법 __getattr____getattribute__마술 방법 의 간단한 예를 살펴 보겠습니다 .

__getattr__

파이썬은 __getattr__아직 정의되지 않은 속성을 요청할 때마다 메소드 를 호출 합니다. 다음 예제에서 내 클래스 Count 에는 __getattr__메소드 가 없습니다 . 이제 주에서 나는 액세스하려고 모두 때 obj1.myminobj1.mymax모든 것이 잘 작동 속성. 그러나 obj1.mycurrent속성 에 액세스하려고하면 Python이AttributeError: 'Count' object has no attribute 'mycurrent'

class Count():
    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax

obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.mycurrent)  --> AttributeError: 'Count' object has no attribute 'mycurrent'

이제 내 클래스 Count 에는 __getattr__메소드가 있습니다. 이제 obj1.mycurrent속성 에 액세스하려고하면 파이썬은 내 __getattr__메소드 에서 구현 한 모든 것을 반환합니다 . 내 예제에서 존재하지 않는 속성을 호출하려고 할 때마다 파이썬은 해당 속성을 만들고 정수 값 0으로 설정합니다.

class Count:
    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax    

    def __getattr__(self, item):
        self.__dict__[item]=0
        return 0

obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.mycurrent1)

__getattribute__

이제 __getattribute__방법을 봅시다. __getattribute__클래스에 메소드가있는 경우 python은 존재 여부에 관계없이 모든 속성에 대해이 메소드를 호출합니다. 왜 우리는 __getattribute__방법이 필요 합니까? 한 가지 좋은 이유는 다음 예제와 같이 속성에 대한 액세스를 방지하고보다 안전하게 만들 수 있기 때문입니다.

누군가가 하위 문자열 ‘cur’로 시작하는 내 속성에 액세스하려고 할 때마다 AttributeError예외 가 발생합니다. 그렇지 않으면 해당 속성을 반환합니다.

class Count:

    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax
        self.current=None

    def __getattribute__(self, item):
        if item.startswith('cur'):
            raise AttributeError
        return object.__getattribute__(self,item) 
        # or you can use ---return super().__getattribute__(item)

obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)

중요 : __getattribute__메소드 에서 무한 재귀를 피하려면 구현시 항상 동일한 이름을 가진 기본 클래스 메소드를 호출하여 필요한 속성에 액세스해야합니다. : 예를 들어, object.__getattribute__(self, name)또는 super().__getattribute__(item)하지self.__dict__[item]

중대한

클래스에 getattrgetattribute 매직 메소드 가 모두 포함 된 경우 __getattribute__먼저 호출됩니다. 그러나 예외 __getattribute__
AttributeError발생하면 예외가 무시되고 __getattr__메소드가 호출됩니다. 다음 예를 참조하십시오.

class Count(object):

    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax
        self.current=None

    def __getattr__(self, item):
            self.__dict__[item]=0
            return 0

    def __getattribute__(self, item):
        if item.startswith('cur'):
            raise AttributeError
        return object.__getattribute__(self,item)
        # or you can use ---return super().__getattribute__(item)
        # note this class subclass object

obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)


답변

이것은 Ned Batchelder의 설명을 기반으로 한 예일뿐입니다 .

__getattr__ 예:

class Foo(object):
    def __getattr__(self, attr):
        print "looking up", attr
        value = 42
        self.__dict__[attr] = value
        return value

f = Foo()
print f.x 
#output >>> looking up x 42

f.x = 3
print f.x 
#output >>> 3

print ('__getattr__ sets a default value if undefeined OR __getattr__ to define how to handle attributes that are not found')

그리고 같은 예제를 사용 __getattribute__하면 >>>RuntimeError: maximum recursion depth exceeded while calling a Python object


답변

새 스타일 클래스는 object또는 다른 새 스타일 클래스에서 상속합니다 .

class SomeObject(object):
    pass

class SubObject(SomeObject):
    pass

구식 수업은하지 않습니다 :

class SomeObject:
    pass

이것은 파이썬 2에만 적용됩니다-파이썬 3에서는 위의 모든 것이 새로운 스타일의 클래스를 만듭니다.

참조 9. 클래스 (파이썬 자습서를) NewClassVsClassicClass파이썬 오래 된 스타일과 새로운 스타일 클래스의 차이점은 무엇입니까? 자세한 내용은.


답변

새로운 스타일 클래스는 “직접”또는 “직접”서브 클래스 인 클래스입니다. 그들은 __new__수업 방법 __init__이 있으며 다소 합리적인 수준의 저수준 행동을합니다.

일반적으로 재정의하고 싶을 __getattr__경우 (중재하는 경우) 메서드 내에서 “self.foo”구문을 지원하는 데 어려움이 있습니다.

추가 정보 : http://www.devx.com/opensource/Article/31482/0/page/4


답변

Beazley & Jones PCB를 통해 읽을 __getattr__때 OP 질문의 “언제”부분에 대한 답변 을 제공하는 명시적이고 실용적인 사용 사례를 발견했습니다 . 책에서 :

“이 __getattr__()방법은 일종의 속성 조회와 비슷합니다. 코드가 존재하지 않는 속성에 액세스하려고하면 호출되는 방법입니다.” 우리는 위의 답변에서 이것을 알고 있지만 PCB 레시피 8.15 에서이 기능은 위임 디자인 패턴 을 구현하는 데 사용됩니다 . 오브젝트 A에 오브젝트 B의 메소드를 호출하기 위해 오브젝트 A의 모든 오브젝트 B 메소드를 재정의하는 대신 오브젝트 A가 위임하려는 많은 메소드를 구현하는 오브젝트 B 속성이있는 경우 __getattr__()다음과 같이 메소드를 정의하십시오 .

def __getattr__(self, name):
    return getattr(self._b, name)

여기서 _b는 오브젝트 B 인 오브젝트 A의 속성 이름입니다. 오브젝트 B에 정의 된 __getattr__메소드가 오브젝트 A에서 호출 되면 메소드는 검색 체인의 끝에서 호출됩니다. 다른 객체에 위임하기 위해 정의 된 메소드 목록이 없기 때문에 코드도 깔끔해집니다.


답변