두 종류의 속성
메서드 안에서 (보통 __init__) self.x = ... 로 정의된 속성은 *인스턴스* 속성 — 각 인스턴스가 자기 거. 클래스 레벨 (메서드 안 X, 클래스 본문) 에 정의된 속성은 *클래스* 속성 — 모든 인스턴스 공유. 둘 다 instance.attribute 로 접근 — 그래서 구분이 미묘.
Lookup 순서 — 인스턴스 먼저, 그 다음 클래스
obj.x 접근하면 Python 은 인스턴스의 __dict__ 먼저 봐. 없으면 클래스 체크. 없으면 상속 체인 위로. 그래서 obj.x = value 가 클래스 속성을 *가리는* 인스턴스 속성 만들어 — 클래스 자체 안 바꿔.
Mutable 클래스 속성 함정
mutable 객체를 클래스 속성으로 (클래스 레벨에 history = []) 두면 모든 인스턴스 공유. instance.history.append(x) 가 가리지 *않고* — 공유 list 변경. mutable 디폴트 인자와 같은 함정. 해결책 — __init__ 안에서 할당 — self.history = [].
주의: 클래스 속성은 진짜 상수와 클래스 전반 설정 (
RETRY_LIMIT = 3) 에 좋고, mutable 한 거엔 나빠. 룰 — 원시 + immutable 이면 클래스 레벨 OK. list / dict / set 이면 인스턴스에.
클래스 레벨 vs 인스턴스 레벨 메서드 — 차이는 __get__
클래스 본문에 정의된 함수가 메서드 되는 이유 — Python 의 descriptor 프로토콜이 접근 시 bound 메서드로 변환. 그래서 self 가 자동으로 나타나. 함수 아닌 클래스 속성은 이 처리 없어 — 자기 자신으로 돌아옴.