언더스코어 뒤에 숨은 이야기 EP09: 속성 접근 (__getattr__, __getattribute__, __setattr__, __delattr__)
카테고리
프로그래밍/소프트웨어 개발
서브카테고리
개발 툴
대상자
- Python 개발자 (중급 이상): 객체 지향 프로그래밍(OOP) 및 속성 접근 메커니즘에 대한 심화 이해가 필요한 분
- 난이도: 중급 (Python의 내부 동작 원리와 재정의 메서드 사용법 이해 필요)
핵심 요약
__getattribute__
: 모든 속성 접근 시 호출됨. 접근 제어, 로깅, 래퍼 구현에 사용 (예:super().__getattribute__(name)
호출 필수).__getattr__
: 속성이 존재하지 않을 때 호출됨. 지연 로딩(Lazy Loading), 기본값 제공, 프록시 객체 구현에 유용.__setattr__
: 속성 할당 시 항상 호출됨. 값 검증, 변환, 로깅에 활용 (예:super().__setattr__(name, value)
호출 필수).__delattr__
: 속성 삭제 시 호출됨. 특정 속성 보호, 정리 로직, 감사 기록에 사용.
섹션별 세부 요약
1. 속성 접근의 기본 동작
- Python은 속성 접근 시 다음과 같은 순서로 처리함:
- 인스턴스의 __dict__
확인
- 클래스 및 부모 클래스 검색
- __getattr__
호출 (속성이 없을 경우)
__getattribute__
는 모든 속성 접근 시 무조건 호출됨 (내장 속성도 포함).
2. `__getattribute__` 예제 및 사용 사례
- 사용 목적:
- 속성 접근 로깅
- 접근 제어 (예: 특정 속성에 대한 권한 검증)
- 동적 행동 추가 (예: 데코레이터 활용)
- 주의사항:
super().__getattribute__(name)
을 반드시 호출해야 재귀 루프를 피함.
3. `__getattr__` 예제 및 사용 사례
- 사용 목적:
- 미리 정의되지 않은 속성에 대한 기본값 제공
- 지연 로딩(Lazy Loading) (예: 필요 시에만 데이터 로드)
- 프록시/래퍼 객체 구현
- 예시:
```python
obj = Lazy()
print(obj.anything) # "anything" 속성이 없으므로 __getattr__ 호출
```
4. `__setattr__` 예제 및 사용 사례
- 사용 목적:
- 할당 값의 검증/변환 (예: 나이 값이 음수가 아닌지 확인)
- 변경 로그 기록
- 특정 속성에 대한 할당 제한
- 예시:
```python
user = Strict()
user.age = 42 # __setattr__ 호출
```
5. `__delattr__` 예제 및 사용 사례
- 사용 목적:
- 특정 속성의 삭제 금지 (예: id
속성 보호)
- 삭제 시 로그 기록/감사
- 중심화된 정리 로직 구현
- 예시:
```python
obj = Guarded()
obj.name = "temp"
del obj.name # __delattr__ 호출
```
6. 조합 사용 예제
- 사용 목적:
- API 래핑, 캐싱 레이어, 도메인 특정 언어(DSL) 구축
- 프레임워크 모델 검증 (예: Django의 모델 필드 검증)
- 예시:
```python
class Magic:
def __getattr__(self, name):
print(f"'{name}' not found. Using default.")
return 42
```
결론
- __getattribute__
를 재정의할 때는 반드시 super().__getattribute__(name)
을 호출해야 재귀 오류를 방지.
- __getattr__
는 미리 정의되지 않은 속성에만 반응하므로, 지연 로딩이나 기본값 제공에 적합.
- __setattr__
와 __delattr__
은 값을 저장/삭제하는 동작을 제어할 때 유용하며, 검증/변환/로그 기능을 추가할 수 있음.
- 실제 구현 시, 모든 메서드의 super()
호출을 반드시 포함하여 Python의 내부 메커니즘을 존중해야 함.