
파이썬 객체 지향 프로그래밍(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.
'Artificial Intelligence > 60. Python' 카테고리의 다른 글
| [PYTHON] 객체 지향의 정점, 클래스 데코레이터와 메타클래스의 3가지 핵심 차이점 및 완벽 해결 가이드 (0) | 2026.03.22 |
|---|---|
| [PYTHON] 런타임에 type()을 활용하여 클래스를 동적으로 생성하는 3가지 방법과 메타프로그래밍의 해결책 (0) | 2026.03.22 |
| [PYTHON] Property 데코레이터를 이용한 캡슐화와 Side Effect 관리 방법 3가지 (0) | 2026.03.22 |
| [PYTHON] 비동기 처리 효율을 높이는 asyncio.gather, wait, as_completed 3가지 핵심 차이와 해결 방법 (0) | 2026.03.22 |
| [PYTHON] Matplotlib와 Plotly 객체 지향 API 활용 방법 3가지와 생산성 차이 해결 (0) | 2026.03.21 |