본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] __getattribute__와 __getattr__의 3가지 결정적 차이와 무한 재귀 해결 방법

by Papa Martino V 2026. 3. 22.
728x90

__getattribute__와 __getattr__
__getattribute__와 __getattr__

 

 

파이썬 객체 지향 프로그래밍(OOP)을 깊이 있게 다루다 보면, 객체의 속성에 접근하는 과정을 제어해야 하는 시점이 옵니다. 이때 가장 혼란스러우면서도 강력한 도구가 바로 __getattr____getattribute__입니다. 이 두 매직 메서드(Magic Method)는 비슷해 보이지만, 호출 시점과 동작 방식에서 극명한 차이를 보입니다. 이를 잘못 이해하면 시스템 전체를 다운시키는 무한 재귀(Infinite Recursion)의 늪에 빠지기 쉽습니다. 본 가이드에서는 시니어 개발자의 관점에서 두 메서드의 내부 메커니즘을 상세히 분석하고, 실무에서 마주치는 무한 재귀 문제를 완벽하게 해결하는 패턴을 제시합니다.


1. 핵심 개념의 이해: 언제 호출되는가?

가장 먼저 이해해야 할 점은 "속성을 찾는 우선순위"입니다. 파이썬은 객체에서 속성을 찾을 때 정해진 순서에 따라 움직입니다.

__getattribute__ (무조건적인 관문)

객체의 속성에 접근하려 할 때 가장 먼저, 그리고 무조건 호출되는 메서드입니다. 속성이 클래스 내부에 존재하든 말든 상관없이 호출됩니다. 따라서 모든 속성 접근을 가로채서 로깅을 하거나 보안 검사를 할 때 유용하지만, 그만큼 위험성도 큽니다.

__getattr__ (최후의 보루)

객체의 일반적인 속성 탐색(__dict__ 검색 등)이 실패했을 때, 즉 AttributeError가 발생하기 직전에만 호출됩니다. 존재하지 않는 속성에 대해 기본값을 제공하거나 동적인 처리를 할 때 적합합니다.


2. 두 메서드의 주요 차이점 비교

두 메서드의 특성을 한눈에 파악할 수 있도록 표로 정리하였습니다.

구분 __getattribute__ __getattr__
호출 시점 모든 속성 접근 시 (무조건) 속성을 찾지 못했을 때만 (선택적)
우선순위 가장 높음 (1순위) 가장 낮음 (최하위)
위험도 매우 높음 (무한 재귀 가능성) 낮음
주요 용도 프록시 패턴, 로깅, 접근 제어 동적 속성 생성, 기본값 처리
오버헤드 비교적 높음 (모든 접근에 개입) 낮음 (실패 시에만 개입)

3. 무한 재귀(Infinite Recursion)가 발생하는 원인과 해결 방법

__getattribute__를 구현할 때 초보 개발자가 가장 많이 실수하는 부분이 바로 무한 재귀입니다. 내부에서 self.name과 같이 속성에 접근하면, 그 접근 자체가 다시 __getattribute__를 호출하게 되어 프로그램이 중단됩니다.

해결 방법: super() 사용하기

재귀를 방지하기 위해서는 인스턴스의 __dict__self에 직접 접근하는 대신, 부모 클래스(주로 object)의 메서드를 호출하여 값을 가져와야 합니다.

# 위험한 예시 (무한 재귀 발생)
def __getattribute__(self, name):
    print(f"Accessing {name}")
    return self.__dict__[name]  # 여기서 다시 __getattribute__가 호출됨!

# 올바른 예시 (해결 방법)
def __getattribute__(self, name):
    print(f"Accessing {name}")
    return super().__getattribute__(name) # 부모의 메서드를 사용하여 우회

4. 실무형 Sample Example: 동적 API 래퍼 구현

다음은 존재하지 않는 속성을 호출했을 때 이를 API 엔드포인트로 매핑하는 __getattr__의 활용 예시입니다.

class DynamicAPI:
    def __init__(self, base_url):
        self.base_url = base_url

    def __getattr__(self, name):
        # 정의되지 않은 메서드 호출 시 API 경로로 인식
        def handler(*args, **kwargs):
            endpoint = f"{self.base_url}/{name}"
            return f"Fetching data from {endpoint} with {args}"
        return handler

# 사용 예시
api = DynamicAPI("https://api.example.com")
print(api.get_users(id=123)) 
# 출력: Fetching data from https://api.example.com/get_users with ()

5. 결론 및 요약

파이썬에서 속성 제어는 매우 강력하지만 신중해야 합니다. 1) 단순한 기본값 설정이나 동적 속성이 필요하다면 __getattr__을 사용하세요. 2) 모든 속성 접근에 대해 엄격한 통제가 필요하다면 __getattribute__를 쓰되, 반드시 super()를 통해 무한 재귀를 방지해야 합니다. 이 두 가지만 기억해도 파이썬 메타 프로그래밍의 수준을 한 단계 높일 수 있습니다.


내용 출처 및 참고 문헌

  • Python Software Foundation. "Data Model - Magic Methods". Official Documentation.
  • Luciano Ramalho. "Fluent Python: Clear, Concise, and Effective Programming". O'Reilly Media.
  • Brett Slatkin. "Effective Python: 90 Specific Ways to Write Better Python". Addison-Wesley.
728x90