3. 데이터 모델

3.1. 객체, 값, 형

객체 (Objects)는 파이썬이 데이터(data)를 추상화한 것(abstraction)이다. 파이썬 프로그램의 모든 데이터는 객체나 객체 간의 관계로 표현된다. (폰 노이만(Von Neumann)의 《프로그램 내장식 컴퓨터(stored program computer)》 모델을 따르고, 또 그 관점에서 코드 역시 객체로 표현된다.)

모든 객체는 아이덴티티(identity), 형(type), 값(value)을 갖는다. 객체의 아이덴티티 는 한 번 만들어진 후에는 변경되지 않는다. 메모리상에서의 객체의 주소로 생각해도 좋다. 〈is〉 연산자는 두 객체의 아이덴티티를 비교한다; id() 함수는 아이덴티티를 정수로 표현한 값을 돌려준다.

CPython implementation detail: CPython 의 경우, id(x)x 가 저장된 메모리의 주소다.

객체의 형은 객체가 지원하는 연산들을 정의하고 (예를 들어, 《길이를 갖고 있나?》) 그 형의 객체들이 가질 수 있는 가능한 값들을 정의한다. type() 함수는 객체의 형(이것 역시 객체다)을 돌려준다. 아이덴티티와 마찬가지로, 객체의 형 (type) 역시 변경되지 않는다. 1

어떤 객체들의 은 변경할 수 있다. 값을 변경할 수 있는 객체들을 가변(mutable) 이라고 한다. 일단 만들어진 후에 값을 변경할 수 없는 객체들을 불변(immutable) 이라고 한다. (가변 객체에 대한 참조를 저장하고 있는 불변 컨테이너의 값은 가변 객체의 값이 변할 때 변경된다고 볼 수도 있다; 하지만 저장하고 있는 객체들의 집합이 바뀔 수 없으므로 컨테이너는 여전히 불변이라고 여겨진다. 따라서 불변성은 엄밀하게는 변경 불가능한 값을 갖는 것과는 다르다. 좀 더 미묘하다.) 객체의 가변성(mutability)은 그것의 형에 의해 결정된다; 예를 들어 숫자, 문자열, 튜플(tuple)은 불변이지만, 딕셔너리(dictionary) 와 리스트(list)는 가변이다.

객체는 결코 명시적으로 파괴되지 않는다; 더 참조되지 않을 때(unreachable) 가비지 수거(garbage collect)된다. 구현이 가비지 수거를 지연시키거나 아예 생략하는 것이 허락된다 — 아직 참조되는 객체들을 수거하지 않는 이상 가비지 수거가 어떤 식으로 구현되는지는 구현의 품질 문제다.

CPython implementation detail: CPython 은 현재 참조 횟수 계산(reference-counting) 방식을 사용하는데, (선택 사항으로) 순환적으로 연결된 가비지의 지연된 감지가 추가된다. 이 방법으로 대부분 객체를 참조가 제거되자마자 수거할 수 있다. 하지만 순환 참조가 있는 가비지들을 수거한다는 보장은 없다. 순환적 가비지 수거의 제어에 관한 정보는 gc 모듈 문서를 참조하면 된다. 다른 구현들은 다른 식으로 동작하고, CPython 도 변경될 수 있다. 참조가 제거될 때 즉각적으로 파이널리제이션(finalization)되는 것에 의존하지 말아야 한다 (그래서 항상 파일을 명시적으로 닫아주어야 한다).

구현이 제공하는 추적이나 디버깅 장치의 사용은 그렇지 않으면 수거될 수 있는 객체들을 살아있도록 만들 수 있음에 주의해야 한다. 또한 〈tryexcept〉 문으로 예외를 잡는 것도 객체를 살아있게 만들 수 있다.

어떤 객체들은 열린 파일이나 창 같은 《외부(external)》 자원들에 대한 참조를 포함한다. 이 자원들은 객체가 가비지 수거될 때 반납된다고 이해되지만, 가비지 수거는 보장되는 것이 아니므로, 그런 객체들은 외부자원을 반납하는 명시적인 방법 또한 제공한다. 보통 close() 메서드다. 프로그램을 작성할 때는 그러한 객체들을 항상 명시적으로 닫아야(close) 한다. 〈tryfinally〉 문과 〈with〉 문은 이렇게 하는 편리한 방법을 제공한다.

어떤 객체들은 다른 객체에 대한 참조를 포함하고 있다. 이런 것들을 컨테이너(container) 라고 부른다. 튜플, 리스트, 딕셔너리등이 컨테이너의 예다. 이 참조들은 컨테이너의 값의 일부다. 대부분은, 우리가 컨테이너의 값을 논할 때는, 들어있는 객체들의 아이덴티티 보다는 값을 따진다. 하지만, 컨테이너의 가변성에 대해 논할 때는 직접 가진 객체들의 아이덴티티만을 따진다. 그래서, (튜플 같은) 불변 컨테이너가 가변 객체로의 참조를 하고 있다면, 그 가변 객체가 변경되면 컨테이너의 값도 변경된다.

형은 거의 모든 측면에서 객체가 동작하는 방법에 영향을 준다. 객체의 아이엔티디가 갖는 중요성조차도 어떤 면에서는 영향을 받는다: 불변형의 경우, 새 값을 만드는 연산은 실제로는 이미 존재하는 객체 중에서 같은 형과 값을 갖는 것을 돌려줄 수 있다. 반면에 가변 객체에서는 이런 것이 허용되지 않는다. 예를 들어, a = 1; b = 1 후에, ab 는 값 1을 갖는 같은 객체일 수도 있고, 아닐 수도 있다. 하지만 c = []; d = [] 후에, cd 는 두 개의 서로 다르고, 독립적이고, 새로 만들어진 빈 리스트임이 보장된다. (c = d = [] 는 객은 객체를 cd 에 대입한다.)

3.2. 표준형 계층

아래에 파이썬에 내장된 형들의 목록이 있다. (구현에 따라 C 나 자바나 다른 언어로 작성된) 확장 모듈들은 추가의 형을 정의할 수 있다. 파이썬의 미래 버전 역시 형 계층에 형을 더할 수 있는데 (예를 들어, 유리수, 효율적으로 저장된 정수 배열 등등), 표준 라이브러리를 통해 추가될 가능성이 더 크기는 하다.

아래에 나오는 몇몇 형에 대한 설명은 〈특수 어트리뷰트(special attribute)〉 를 나열하는 문단을 포함한다. 이것들은 구현에 접근할 방법을 제공하는데, 일반적인 사용을 위한 것이 아니다. 정의는 앞으로 변경될 수 있다.

None

이 형은 하나의 값만을 갖는다. 이 값을 갖는 하나의 객체가 존재한다. 이 객체에는 내장된 이름 None 을 통해 접근한다. 여러 가지 상황에서 값의 부재를 알리는 데 사용된다. 예를 들어, 명시적으로 뭔가를 돌려주지 않는 함수의 반환 값이다. 논리값은 거짓이다.

NotImplemented

이 형은 하나의 값만을 갖는다. 이 값을 갖는 하나의 객체가 존재한다. 이 객체에는 내장된 이름 NotImplemented 을 통해 접근한다. 숫자 메서드(numeric method)와 비교(rich comparison) 메서드는 제공된 피연산자에 대해 연산이 구현되지 않으면 이 값을 돌려줘야 한다. (그러면 인터프리터는 연산자에 따라 뒤집힌 연산이나, 어떤 다른 대안을 시도한다.) 논리값은 참이다.

더 자세한 내용은 산술 연산 구현 을 참고하라.

Ellipsis

이 형은 하나의 값만을 갖는다. 이 값을 갖는 하나의 객체가 존재한다. 이 객체에는 리터럴 ... 이나 내장된 이름 Ellipsis 을 통해 접근한다. 논리값은 참이다.

numbers.Number

이것들은 숫자 리터럴에 의해 만들어지고, 산순 연산과 내장 산술 함수들이 결과로 돌려준다. 숫자 객체는 불변이다; 한 번 값이 만들어지면 절대 변하지 않는다. 파이썬의 숫자는 당연히 수학적인 숫자들과 밀접하게 관련되어 있다, 하지만 컴퓨터의 숫자 표현상의 제약을 받고 있다.

파이썬은 정수, 실수, 복소수를 구분한다:

numbers.Integral

이것들은 수학적인 정수 집합(양과 음)에 속하는 요소들을 나타낸다.

두 가지 종류의 정수가 있다:

정수 (int)

이것은 (가상) 메모리가 허락하는 한, 제약 없는 범위의 숫자를 표현한다. 시프트(shift)와 마스크(mask) 연산이 목적일 때는 이진 표현이 가정되고, 음수는 일종의 2의 보수(2’s complement)로 표현되는데, 부호 비트가 왼쪽으로 무한히 확장된 것과 같은 효과를 준다.

불린 (bool)

이것은 논리값 거짓과 참을 나타낸다. FalseTrue 두 객체만 불린 형 객체다. 불린 형은 int 형의 자식형(subtype)이고, 대부분 상황에서 각기 0과1처럼 동작한다. 예외는 문자열로 변환되는 경우인데, 각기 문자열 "False""True" 가 반환된다.

정수 표현 규칙은 음수가 포함된 시프트와 마스크 연산에 가장 의미 있는 해석을 제공하기 위한 것이다.

numbers.Real (float)

이것들은 기계 수준의 배정도(double precision) 부동 소수점 수를 나타낸다. 허락되는 값의 범위와 오버플로의 처리에 관해서는 하부 기계의 설계(와 C 나 자바 구현)에 따르는 수밖에 없다. 파이썬은 단정도(single precision) 부동 소수점 수를 지원하지 않는다; 이것들을 사용하는 이유가 되는 프로세서와 메모리의 절감은 파이썬에서 객체를 사용하는데 들어가는 비용과 상쇄되어 미미해진다. 그 때문에 두 가지 종류의 부동 소수점 수로 언어를 복잡하게 만들만한 가치가 없다.

numbers.Complex (complex)

이것들은 기계 수준 배정도 부동 소수점 수의 쌍으로 복소수를 나타낸다. 부동 소수점 수와 한계와 문제점을 공유한다. 복소수 z 의 실수부와 허수부는, 읽기 전용 어트리뷰트 z.realz.imag 로 꺼낼 수 있다.

시퀀스들

음이 아닌 정수로 인덱싱(indexing)될 수 있는 유한한 길이의 순서 있는 집합을 나타낸다. 내장함수 len() 은 시퀀스가 가진 항목들의 개수를 돌려준다. 시퀀스의 길이가 n 일 때, 인덱스(index) 집합은 숫자 0, 1, …, n-1을 포함한다. 시퀀스 a 의 항목 ia[i] 로 선택된다.

시퀀스는 슬라이싱도 지원한다: a[i:j]i <= k < j 를 만족하는 모든 항목 k 를 선택한다. 표현식에서 사용될 때, 슬라이스는 같은 형의 시퀀스다. 인덱스 집합은 0에서 시작되도록 다시 번호 매겨진다.

어떤 시퀀스는 세 번째 《스텝(step)》 파라미터를 사용하는 《확장 슬라이싱(extended slicing)》도 지원한다: a[i:j:k]x = i + n*k, n >= 0, i <= x < j 를 만족하는 모든 항목 x 를 선택한다.

시퀀스는 불변성에 따라 구분된다

불변 시퀀스

불변 시퀀스 형의 객체는 일단 만들어진 후에는 변경될 수 없다. (만약 다른 객체로의 참조를 포함하면, 그 객체는 가변일 수 있고, 변경될 수 있다; 하지만, 불변 객체로부터 참조되는 객체의 집합 자체는 변경될 수 없다.)

다음과 같은 형들은 불변 시퀀스다:

문자열(Strings)

문자열은 유니코드 코드 포인트(Unicode code point)들을 표현하는 값들의 시퀀스다. U+0000 - U+10FFFF 범위의 모든 코드 포인트들은 문자열로 표현될 수 있다. 파이썬에는 char 형이 없다. 대신에 문자열에 있는 각 코드 포인트는 길이 1 인 문자열 객체로 표현된다. 내장 함수 ord() 는 코드 포인트를 문자열 형식에서 0 - 10FFFF 범위의 정수로 변환한다; chr() 은 범위 0 - 10FFFF 의 정수를 해당하는 길이 1 의 문자열 객체로 변환한다. str.encode() 는 주어진 텍스트 인코딩을 사용해서 strbytes 로 변환하고, bytes.decode() 는 그 반대 작업을 수행한다.

튜플(Tuples)

튜플의 항목은 임의의 파이썬 객체다. 두 개 이상의 항목으로 구성되는 튜플은 콤마로 분리된 표현식의 목록으로 만들 수 있다. 하나의 항목으로 구성된 튜플(싱글턴,singleton)은 표현식에 콤마를 붙여서 만들 수 있다(괄호로 표현식을 묶을 수 있으므로, 표현식 만으로는 튜플을 만들지 않는다). 빈 튜플은 한 쌍의 빈 괄호로 만들 수 있다.

바이트열(Bytes)

바이트열(bytes) 객체는 불변 배열이다. 항목은 8-비트 바이트인데, 0 <= x < 256 범위의 정수로 표현된다. 바이트 객체를 만들 때는 바이트열 리터럴(b'abc' 와 같은) 과 내장 bytes() 생성자(constructor)를 사용할 수 있다. 또한, 바이트열 객체는 decode() 메서드를 통해 문자열로 디코딩될 수 있다.

가변 시퀀스

가변 시퀀스는 만들어진 후에 변경될 수 있다. 서브스크립션(subscription)과 슬라이싱은 대입문과 del (삭제) 문의 대상으로 사용될 수 있다.

현재 두 개의 내장 가변 시퀀스형이 있다:

리스트(Lists)

리스트의 항목은 임의의 파이썬 객체다. 리스트는 콤마로 분리된 표현식을 꺾쇠괄호 안에 넣어서 만들 수 있다. (길이 0이나 1의 리스트를 만드는데 별도의 규칙이 필요 없다.)

바이트 배열(Byte Arrays)

비이트 배열(bytearray) 객체는 가변 배열이다. 내장 bytearray() 생성자로 만들어진다. 가변이라는 것(그래서 해싱 불가능하다는 것)을 제외하고, 바이트 배열은 불변 바이트열( bytes) 객체와 같은 인터페이스와 기능을 제공한다.

확장 모듈 array 는 추가의 가변 시퀀스 형을 제공하는데, collections 모듈 역시 마찬가지다.

집합 형들(Set types)

이것들은 중복 없는 불변 객체들의 순서 없고 유한한 집합을 나타낸다. 인덱싱할 수 없다. 하지만 이터레이트할 수 있고, 내장 함수 len() 은 집합 안에 있는 항목들의 개수를 돌려준다. 집합의 일반적인 용도는 빠른 멤버십 검사(fast membership testing), 시퀀스에서 중복된 항목 제거, 교집합(intersection), 합집합(union), 차집합(difference), 대칭차집합(symmetric difference)과 같은 집합 연산을 계산하는 것이다.

집합의 원소들에는 딕셔너리 키와 같은 불변성 규칙이 적용된다. 숫자 형의 경우는 숫자 비교에 관한 일반 원칙이 적용된다는 점에 주의해야 한다: 만약 두 숫자가 같다고 비교되면(예를 들어, 1``과 ``1.0), 그중 하나만 집합에 들어갈 수 있다.

현재 두 개의 내장 집합 형이 있다:

집합(Sets)

이것들은 가변 집합을 나타낸다. 내장 set() 생성자로 만들 수 있고, add() 같은 메서드들을 사용해서 나중에 수정할 수 있다.

불변 집합(Frozen sets)

이것들은 불변 집합을 나타낸다. 내장 frozenset() 생성자로 만들 수 있다. 불변 집합(frozenset)은 불변이고 해시 가능 하므로, 다른 집합의 원소나, 딕셔너리의 키로 사용될 수 있다.

매핑(Mappings)

이것들은 임의의 인덱스 집합으로 인덱싱되는 객체들의 유한한 집합을 나타낸다. 인덱스 표기법(subscript notation) a[k] 는 매핑 a 에서 k 로 인덱스 되는 항목을 선택한다; 이것은 표현식에 사용될 수도 있고, 대입이나 del 문장의 대상이 될 수도 있다. 내장 함수 len() 은 매핑에 포함된 항목들의 개수를 돌려준다.

현재 한 개의 내장 매핑 형이 있다:

딕셔너리(Dictionaries)

이것들은 거의 임의의 인덱스 집합으로 인덱싱되는 객체들의 유한한 집합을 나타낸다. 키로 사용할 수 없는 것들은 리스트, 딕셔너리나 그 외의 가변형 중에서 아이덴티티가 아니라 값으로 비교되는 것들뿐이다. 딕셔너리의 효율적인 구현이, 키의 해시값이 도중에 변경되지 않고 계속 같은 값으로 유지되도록 요구하고 있기 때문이다. 키로 사용되는 숫자 형의 경우는 숫자 비교에 관한 일반 원칙이 적용된다: 만약 두 숫자가 같다고 비교되면(예를 들어, 1``과 ``1.0), 둘 다 같은 딕셔너리 항목을 인덱싱하는데 사용될 수 있다.

딕셔너리는 가변이다; {...} 표기법으로 만들 수 있다 (딕셔너리 디스플레이 섹션을 참고하라).

확장 모듈 dbm.ndbmdbm.gnu 는 추가의 매핑 형을 제공하는데, collections 모듈 역시 마찬가지다.

콜러블(Callable types)

이것들은 함수 호출 연산(호출 섹션 참고)이 적용될 수 있는 형들이다:

사용자 정의 함수

사용자 정의 함수 객체는 함수 정의를 통해 만들어진다 (함수 정의 섹션 참고). 함수의 형식 파라미터(formal parameter) 목록과 같은 개수의 항목을 포함하는 인자(argument) 목록으로 호출되어야 한다.

특수 어트리뷰트들(Special attributes):

어트리뷰트

의미

__doc__

함수를 설명하는 문자열 또는 없는 경우 None; 서브 클래스로 상속되지 않는다

쓰기 가능

__name__

함수의 이름

쓰기 가능

__qualname__

함수의 정규화된 이름

버전 3.3에 추가.

쓰기 가능

__module__

함수가 정의된 모듈의 이름 또는 (없는 경우) None

쓰기 가능

__defaults__

인자의 기본값 또는 (없는 경우) None 으로 만들어진 튜플

쓰기 가능

__code__

컴파일된 함수의 바디(body) 를 나타내는 코드 객체

쓰기 가능

__globals__

함수의 전역 변수들을 가진 딕셔너리에 대한 참조 — 함수가 정의된 모듈의 전역 이름 공간(namespace)

읽기 전용

__dict__

임의의 함수 어트리뷰트를 지원하는 이름 공간.

쓰기 가능

__closure__

None 또는 함수의 자유 변수(free variable)들에 대한 연결을 가진 셀(cell)들의 튜플.

읽기 전용

__annotations__

파라미터의 어노테이션을 가진 dict. dict 의 키는 파라미터의 이름인데, 반환 값 어노테이션이 있다면 'return' 을 키로 사용한다.

쓰기 가능

__kwdefaults__

키워드 형태로만 전달 가능한 파라미터들의 기본값을 가진 dict.

쓰기 가능

《쓰기 가능》 하다고 표시된 대부분의 어트리뷰트들은 값이 대입될 때 형을 검사한다.

함수 객체는 임의의 어트리뷰트를 읽고 쓸 수 있도록 지원하는데, 예를 들어 함수에 메타데이터(metadata)를 붙이는데 사용될 수 있다. 어트리뷰트를 읽거나 쓸 때는 일반적인 점 표현법(dot-notation)이 사용된다. 현재 구현은 오직 사용자 정의 함수만 함수 어트리뷰트를 지원함에 주의해야 한다. 내장 함수의 함수 어트리뷰트는 미래에 지원될 수 있다.

함수 정의에 관한 추가적인 정보를 코드 객체로부터 얻을 수 있다. 아래에 나오는 내부 형의 기술을 참고하라.

인스턴스 메서드(Instance methods)

인스턴스 메서드는 클래스, 클래스 인스턴스와 모든 콜러블 객체 (보통 사용자 정의 함수)을 결합한다.

특수 읽기 전용 어트리뷰트들: __self__ 는 클래스 인스턴스 객체, __func__ 는 함수 객체; __doc__ 은 메서드의 설명 (__func__.__doc__ 과 같다); __name__ 은 메서드의 이름 (__func__.__name__ 과 같다); __module__ 은 메서드가 정의된 모듈의 이름이거나 없는 경우 None.

메서드는 기반 함수의 모든 함수 어트리뷰트들을 읽을 수 있도록 지원한다(하지만 쓰기는 지원하지 않는다).

어트리뷰트가 사용자 정의 함수 객체이거나 클래스 메서드 객체면, 사용자 정의 메서드 객체는 클래스의 어트리뷰트를 읽을 때 만들어질 수 있다 (아마도 그 클래스의 인스턴스를 통해서).

인스턴스 메서드 객체가 클래스 인스턴스를 통해 클래스의 사용자 정의 함수 객체를 읽음으로써 만들어질 때, __self__ 어트리뷰트는 인스턴스이고, 메서드 객체는 결합(bound)하였다고 말한다. 새 메서드의 __func__ 어트리뷰트는 원래의 함수 객체다.

클래스나 인스턴스로부터 다른 메서드 객체를 읽음으로써 사용자 정의 메서드 객체가 만들어질 때, 새 인스턴스의 __func__ 어트리뷰트가 원래의 메서드 객체가 아니라, 그것의 __func__ 어트리뷰트라는 점만 제외하고는 함수 객체의 경우와 같은 방식으로 동작한다.

인스턴스 메서드 객체가 클래스나 인스턴스로부터 클래스 메서드 객체를 읽음으로써 만들어질 때, __self__ 어트리뷰트는 클래스 자신이고, __func__ 어트리뷰트는 클래스 메서드가 기반을 두는 함수 객체다.

인스턴스 메서드 객체가 호출될 때, 기반을 두는 함수 (__func__) 가 호출되는데, 인자 목록의 앞에 클래스 인스턴스 (__self__) 가 삽입된다. 예를 들어, C 가 함수 f() 의 정의를 포함하는 클래스이고, xC 의 인스턴스일 때, x.f(1) 를 호출하는 것은 C.f(x, 1) 을 호출하는 것과 같다.

인스턴스 메서드 객체가 클래스 메서드 객체로부터 올 때, __self__ 에 저장된 《클래스 인스턴스》 는 실제로는 클래스 자신이다. 그래서 x.f(1) 이나 C.f(1) 을 호출하는 것은 f(C,1) 를 호출하는 것과 같다 (f 는 기반 함수다).

함수 객체에서 인스턴스 객체로의 변환은 인스턴스로부터 어트리뷰트를 읽을 때마다 일어남에 주의해야 한다. 어떤 경우에, 어트리뷰트를 지역 변수에 대입하고, 그 지역 변수를 호출하는 것이 효과적인 최적화가 된다. 또한, 이 변환이 사용자 정의 함수에 대해서만 발생함에 주의해야 한다; 다른 콜러블 객체 (그리고 콜러블이 아닌 모든 객체)는 변환 없이 읽힌다. 클래스 인스턴스의 어트리뷰트인 사용자 정의 함수는 결합한 메서드로 변환되지 않는다는 것도 중요하다; 이 변환은 함수가 클래스 어트리뷰트일 때만 일어난다.

제너레이터 함수(Generator functions)

yield 문(yield 문 절 참조)을 사용하는 함수나 메서드를 제너레이터 함수 (generator function) 라고 부른다. 이런 함수를 호출하면 항상 이터레이터(iterator) 객체를 돌려주는데, 함수의 바디(body)를 실행하는 데 사용된다: 이터레이터의 iterator.__next__() 메서드를 호출하면 yield 문이 값을 제공할 때까지 함수가 실행된다. 함수가 return 문을 실행하거나 끝에 도달하면 StopIteration 예외를 일으키고, 이터레이터는 반환하는 값들의 끝에 도달하게 된다.

코루틴 함수(Coroutine functions)

async def 를 사용해서 정의되는 함수나 메서드를 코루틴 함수 (coroutine function) 라고 부른다. 이런 함수를 호출하면 코루틴 객체를 돌려준다. await 표현식을 비롯해, async withasync for 문을 사용할 수 있다. 코루틴 객체(Coroutine Objects) 섹션을 참조.

비동기 제너레이터 함수(Asynchronous generator functions)

async def 를 사용해서 정의되는 함수가 yield 문을 사용하면 비동기 제너레이터 함수 (asynchronous generator function) 라고 부른다. 이런 함수를 호출하면 항상 비동기 이터레이터(asynchronous iterator) 객체를 돌려주는데, 함수의 바디(body)를 실행하기 위해 async for 문에서 사용된다.

비동기 이터레이터의 aiterator.__anext__() 메서드를 호출하면 어웨이터블 을 돌려주는데, await 할 때 yield 문이 값을 제공할 때까지 함수가 실행된다. 함수가 빈 return 문을 실행하거나 끝에 도달하면 StopAsyncIteration 예외를 일으키고, 비동기 이터레이터는 반환하는 값들의 끝에 도달하게 된다.

내장 함수(Built-in functions)

내장 함수 객체는 C 함수를 둘러싸고 있다(wrapper). 내장 함수의 예로는 len()math.sin() (math 는 표준 내장 모듈이다) 가 있다. 인자의 개수와 형은 C 함수에 의해 결정된다. 특수 읽기 전용 어트리뷰트들: __doc__ 은 함수의 설명 문자열 또는 없는 경우 None 이다; __name__ 은 함수의 이름이다; __self__None 으로 설정된다 (하지만 다음 항목을 보라); __module__ 은 함수가 정의된 모듈의 이름이거나 없는 경우 None 이다.

내장 메서드(Built-in methods)

이것은 사실 내장 함수의 다른 모습이다. 이번에는 묵시적인 추가의 인자로 C 함수에 전달되는 객체를 갖고 있다. 내장 메서드의 예로는 alist.append() 가 있는데, alist 는 리스트 객체다. 이 경우에, 특수 읽기 전용 어트리뷰트 __self__alist 로 표현된 객체로 설정된다.

클래스(Classes)

클래스는 콜러블이다. 이 객체들은 보통 자신의 새로운 인스턴스를 만드는 팩토리(factory)로 동작하는데, __new__() 메서드를 재정의(override) 하는 클래스 형에서는 달라질 수도 있다. 호출 인자는 __new__() 로 전달되고, 일반적으로, 새 인스턴스를 초기화하기 위해 __init__() 로도 전달된다.

클래스 인스턴스(Class Instances)

클래스에서 __call__() 메서드를 정의함으로써, 클래스 인스턴스를 콜러블로 만들 수 있다.

모듈(Modules)

모듈은 파이썬 코드의 기본적인 조직화 단위이고, import 문(import 를 참고)이나, importlib.import_module() 과 내장 __import__() 함수를 호출해서 구동할 수 있는 임포트 시스템 에 의해 만들어진다. 모듈 객체는 딕셔너리 객체로 구현되는 이름 공간을 갖는다(이 딕셔너리 객체는 모듈에서 정의되는 함수들의 __globals__ 어트리뷰트로 참조된다). 어트리뷰트 참조는 이 딕셔너리에 대한 조회로 변환된다. 예를 들어, m.xm.__dict__["x"] 와 같다. 모듈 객체는 모듈을 초기화하는데 사용된 코드 객체를 갖고 있지 않다 (일단 초기화가 끝나면 필요 없으므로).

어트리뷰트 대입은 모듈의 이름 공간 딕셔너리를 갱신한다. 예를 들어, m.x = 1m.__dict__["x"] = 1 과 같다.

미리 정의된 (쓰기 가능한) 어트리뷰트들: __name__ 은 모듈의 이름이다; __doc__ 은 모듈의 설명 문자열 또는 없는 경우 None 이다; (없을 수도 있는) __annotations__ 는 모듈의 바디를 실행하면서 수집된 변수 어노테이션 들을 담은 딕셔너리다; __file__ 은 모듈이 로드된 파일의 경로명이다. 인터프리터에 정적으로 연결된 C 모듈과 같은 어떤 종류의 모듈들에서는 __file__ 어트리뷰트가 제공되지 않는다; 공유 라이브러리(shared library)로부터 동적으로 로딩되는 확장 모듈의 경우 공유 라이브러리의 경로명이 제공된다.

특수 읽기 전용 어트리뷰트들: __dict__ 는 딕셔너리로 표현되는 모듈의 이름 공간이다.

CPython implementation detail: CPython 이 모듈 딕셔너리를 비우는 방법 때문에, 딕셔너리에 대한 참조가 남아있더라도, 모듈이 스코프를 벗어나면 모듈 딕셔너리는 비워진다. 이것을 피하려면, 딕셔너리를 복사하거나 딕셔너리를 직접 이용하는 동안은 모듈을 잡아두어야 한다.

사용자 정의 클래스(Custom classes)

사용자 정의 클래스 형들은 보통 클래스 정의 때문에 만들어진다 (클래스 정의 섹션 참조). 클래스는 딕셔너리로 구현된 이름 공간을 갖는다. 클래스 어트리뷰트 참조는 이 딕셔너리에 대한 조회로 변환된다. 예를 들어, C.xC.__dict__["x"] 로 변환된다 (하지만 어트리뷰트에 접근하는 다른 방법들을 허락하는 여러 가지 훅(hook)이 있다.). 거기에서 어트리뷰트 이름이 발견되지 않으면, 어트리뷰트 검색은 부모 클래스들에서 계속된다. 이 부모 클래스 검색은 C3 메서드 결정 순서(method resolution order)를 사용하는데, 다중 상속이 같은 부모 클래스로 모이는 〈다이아몬드(diamond)〉 계승 구조가 존재해도 올바르게 동작한다. 파이썬이 사용하는 C3 MRO에 관한 좀 더 자세한 내용은 2.3 배포에 첨부된 문서 https://www.python.org/download/releases/2.3/mro/ 에서 찾아볼 수 있다.

When a class attribute reference (for class C, say) would yield a class method object, it is transformed into an instance method object whose __self__ attribute is C. When it would yield a static method object, it is transformed into the object wrapped by the static method object. See section 디스크립터 구현하기 for another way in which attributes retrieved from a class may differ from those actually contained in its __dict__.

클래스 어트리뷰트 대입은 클래스의 딕셔너리를 갱신할 뿐, 어떤 경우도 부모 클래스의 딕셔너리를 건드리지는 않는다.

클래스 객체는 클래스 인스턴스를 돌려주도록(아래를 보라) 호출될 수 있다(위를 보라).

특수 어트리뷰트들:__name__ 은 클래스의 이름이다. __module__ 은 클래스가 정의된 모듈의 이름이다. __dict__ 는 클래스의 이름 공간을 저장하는 딕셔너리다; __bases__ 는 부모 클래스들을 저장하는 튜플이다; 부모 클래스 목록에 나타나는 순서를 유지한다; __doc__ 은 클래스의 설명 문자열 이거나 정의되지 않으면 None 이다; (없을 수 있는) __annotations__ 는 클래스의 바디를 실행하면서 수집된 변수 어노테이션 들을 담은 딕셔너리다.

클래스 인스턴스(Class instances)

클래스 인스턴스는 클래스 객체를 호출해서 (위를 보라) 만들어진다. 클래스 인스턴스는 딕셔너리로 구현되는 이름 공간을 갖는데, 어트리뷰트를 참조할 때 가장 먼저 검색되는 곳이다. 그곳에서 어트리뷰트가 발견되지 않고, 인스턴스의 클래스가 그 이름의 어트리뷰트를 갖고 있으면, 클래스 어트리뷰트로 검색이 계속된다. 만약 발견된 클래스 어트리뷰트가 사용자 정의 함수면, __self__ 어트리뷰트가 인스턴스인 인스턴스 메서드로 변환된다. 스태틱 메서드와 클래스 메서드 객체 또한 변환된다. 위의 《사용자 정의 클래스(Custom Classes)》 부분을 보라. 클래스로부터 얻은 어트리뷰트가 클래스의 __dict__ 에 저장된 값과 달라지도록 만드는 다른 방법이 디스크립터 구현하기 섹션에 나온다. 만약 클래스 어트리뷰트도 발견되지 않고, 클래스가 __getattr__() 메서드를 가지면, 조회를 만족시키기 위해 그 메서드를 호출한다.

어트리뷰트 대입과 삭제는 인스턴스의 딕셔너리를 갱신할 뿐, 결코 클래스의 딕셔너리를 건드리지 않는다. 만약 클래스가 __setattr__() 이나 __delattr__() 메서드를 가지면, 인스턴스의 딕셔너리를 갱신하는 대신에 그 메서드들을 호출한다.

어떤 특별한 이름들의 메서드들을 가지면, 클래스 인스턴스는 숫자, 시퀀스, 매핑인 척할 수 있다. 특수 메서드 이름들 섹션을 보라.

특수 어트리뷰트들: __dict__ 는 어트리뷰트 딕셔너리다; __class__ 는 인스턴스의 클래스다.

I/O 객체 (파일 객체라고도 알려져 있다)

파일 객체 는 열린 파일을 나타낸다. 파일 객체를 만드는 여러 가지 단축법이 있다: open() 내장 함수, os.popen(), os.fdopen() 과 소켓 객체의 makefile() 메서드 (그리고, 아마도 확장 모듈들이 제공하는 다른 함수들이나 메서드들).

sys.stdin, sys.stdout, sys.stderr 는 인터프리터의 표준 입력, 출력, 에러 스트림으로 초기화된 파일 객체들이다; 모두 텍스트 모드로 열려서 io.TextIOBase 추상 클래스에 의해 정의된 인터페이스를 따른다.

내부 형(Internal types)

인터프리터가 내부적으로 사용하는 몇몇 형들은 사용자에게 노출된다. 인터프리터의 미래 버전에서 이들의 정의는 변경될 수 있지만, 완전함을 위해 여기서 언급한다.

코드 객체(Code objects)

코드 객체는 바이트로 컴파일된(byte-compiled) 실행 가능한 파이썬 코드를 나타내는데, 그냥 바이트 코드 라고도 부른다. 코드 객체와 함수 객체 간에는 차이가 있다; 함수 객체는 함수의 전역 공간(globals) (함수가 정의된 모듈)을 명시적으로 참조하고 있지만, 코드 객체는 어떤 문맥(context)도 갖고 있지 않다; 또한 기본 인자값들이 함수 객체에 저장되어 있지만 코드 객체에는 들어있지 않다 (실행 시간에 계산되는 값들을 나타내기 때문이다). 함수 객체와는 달리, 코드 객체는 불변이고 가변 객체들에 대한 어떤 참조도 (직접 혹은 간접적으로도) 갖고 있지 않다.

특수 읽기 전용 어트리뷰트들: co_name 은 함수의 이름이다; co_argcount 는 위치 인자들 (기본값이 있는 인자들도 포함된다)의 개수다; co_nlocals 는 함수가 사용하는 지역 변수들 (인자들을 포함한다)의 개수다; co_varnames 는 지역 변수들의 이름을 담고 있는 튜플이다(인자들의 이름이 먼저 나온다); co_cellvars 는 중첩된 함수들이 참조하는 지역 변수들의 이름을 담고 있는 튜플이다; co_freevars 는 자유 변수(free variables)들의 이름을 담고 있는 튜플이다; co_code 는 바이트 코드 명령 시퀀스를 나타내는 문자열이다; co_consts 는 바이트 코드가 사용하는 리터럴을 포함하는 튜플이다; co_names 는 바이트 코드가 사용하는 이름들을 담고 있는 튜플이다; co_filename 은 컴파일된 코드를 제공한 파일의 이름이다; co_firstlineno 는 함수의 첫 번째 줄 번호다; co_lnotab 은 바이트 코드에서의 위치를 줄 번호로 매핑하는 법을 문자열로 인코딩한 값이다 (자세한 내용은 인터프리터의 소스 코드를 참고하라); co_stacksize 는 필요한 스택의 크기다 (지역 변수를 포함한다); co_flags 는 인터프리터의 여러 플래그(flag)들을 정수로 인코딩한 값이다.

다음과 같은 값들이 co_flags 를 위해 정의되어 있다: 함수가 가변 개수의 위치 인자를 받아들이기 위해 사용되는 *arguments 문법을 사용하면 비트 0x04 가 1이 된다; 임의의 키워드 인자를 받아들이기 위해 사용하는 **keywords 문법을 사용하면 비트 0x08 이 1이 된다; 비트 0x20 은 함수가 제너레이터일 때 설정된다.

퓨처 기능 선언 (from __future__ import division) 또한 코드 객체가 특정 기능이 활성화된 상태에서 컴파일되었는지를 나타내기 위해 co_flags 의 비트들을 사용한다: 함수가 퓨처 division이 활성화된 상태에서 컴파일되었으면 비트 0x2000 이 설정된다; 비트 0x100x1000 는 예전 버전의 파이썬에서 사용되었다.

co_flags 의 다른 비트들은 내부 사용을 위해 예약되어 있다.

만약 코드 객체가 함수를 나타낸다면, co_consts 의 첫 번째 항목은 설명 문자열이거나 정의되지 않으면 None 이다.

프레임 객체(Frame objects)

프레임 객체는 실행 프레임(execution frame)을 나타낸다. 트레이스백 객체에 등장할 수 있다 (아래를 보라).

특수 읽기 전용 어트리뷰트들: f_back 은 이전 스택 프레임 (호출자 방향으로)을 가리키거나 이게 스택의 바닥이라면 None; f_code 는 이 프레임에서 실행되는 코드 객체; f_locals 는 지역 변수를 조회하는데 사용되는 딕셔너리; f_globals 는 전역 변수에 사용된다; f_builtins 는 내장된(intrinsic) 이름들에 사용된다; f_lasti 는 정확한 바이트 코드 명령(instruction)을 제공한다 (코드 객체의 바이트 코드 문자열에 대한 인덱스다).

특수 쓰기 가능 어트리뷰트들: f_trace 는, None 이 아니면, 각 소스 코드 줄을 시작할 때 호출되는 함수다 (디버거에서 사용된다); f_lineno 는 프레임의 현재 줄 번호다 — 트레이스 함수(f_trace)에서 이 값을 쓰면 해당 줄로 점프한다 (오직 가장 바닥 프레임에서만 가능하다). 디버거는 f_lineno 를 쓰기 위한 점프 명령을 구현할 수 있다 (소위 Set Next Statement).

프레임 객체는 한가지 메서드를 지원한다:

frame.clear()

이 메서드는 프레임이 잡은 지역 변수들에 대한 모든 참조를 제거한다. 또한, 만약 프레임이 제너레이터에 속하면, 제너레이터가 종료된다(finalize). 이것은 프레임 객체가 관련된 참조 순환을 깨는 데 도움을 준다 (예를 들어, 예외를 잡아서 트레이스백을 추후 사용을 위해 저장할 때).

만약 프레임이 현재 실행 중이면 RuntimeError 예외가 발생한다.

버전 3.4에 추가.

트레이스백 객체(Traceback objects)

트레이스백 객체는 예외의 스택 트레이스를 나타낸다. 트레이스백 객체는 예외가 발생할 때 만들어진다. 예외 처리기를 찾아서 실행 스택을 되감을 때, 각각 되감기 단계마다 현재 트레이스백의 앞에 트레이스백 객체를 삽입한다. 예외 처리기에 들어가면, 스택 트레이스를 프로그램이 사용할 수 있다. (try 문 섹션 참조.) sys.exc_info() 가 돌려주는 튜플의 세 번째 항목에 있다. 프로그램이 적절한 처리기를 제공하지 않는 경우, 스택 트레이스는 표준 에러 스트림으로 (보기 좋게 포맷되어) 출력된다; 만약 인터프리터가 대화형이면, sys.last_traceback 으로 사용자에게 제공한다.

특수 읽기 전용 어트리뷰트들: tb_next 는 스택 트레이스의 다음 단계 (예외가 발생한 프레임 방향으로)이거나 다음 단계가 없으면 None 이다. tb_frame 은 현 단계에서의 실행 프레임이다; tb_lineno 는 예외가 발생한 줄의 번호를 준다; tb_lasti 정확한 바이트 코드 명령을 가리킨다. 만약 예외가 except 절이나 finally 절이 없는 try 문에서 발생하면, 줄 번호와 트레이스백의 마지막 명령(last instruction)은 프레임 객체의 줄 번호와 다를 수 있다.

슬라이스 객체(Slice objects)

슬라이스 객체는 __getitem__() 메서드를 위한 슬라이스를 나타낸다. 내장 함수 slice() 로 만들 수도 있다.

특수 읽기 전용 어트리뷰트들: start 는 하한(lower bound) 이다; stop 은 상한(upper bound) 이다; step 은 스텝 값이다; 각 값은 생략될 경우 None 이다. 이 어트리뷰트들은 임의의 형이 될 수 있다.

슬라이스 객체는 하나의 메서드를 지원한다.

slice.indices(self, length)

이 메서드는 하나의 정수 인자 length 를 받아서 슬라이스 객체가 길이 length 인 시퀀스에 적용되었을 때 그 슬라이스에 대한 정보를 계산한다. 세 개의 정수로 구성된 튜플을 돌려준다: 이것들은 각각 startstop 인덱스와, step 또는 슬라이스의 스트라이드(stride) 길이다. 생략되었거나 범위를 벗어난 인덱스들은 일반적인 슬라이스와 같은 방법으로 다뤄진다.

스태틱 메서드 객체(Static method objects)

스태틱 메서드 객체는 위에서 설명한 함수 객체를 메서드 객체로 변환하는 과정을 방지하는 방법을 제공한다. 스태틱 메서드 객체는 다른 임의의 객체, 보통 사용자 정의 메서드를 둘러싼다. 스태틱 메서드가 클래스나 클래스 인스턴스로부터 읽힐 때 객체가 실제로 돌려주는 것은 둘러싸여 있던 객체인데, 다른 어떤 변환도 적용되지 않은 상태다. 둘러싸는 객체는 그렇더라도, 스태틱 메서드 객체 자체는 콜러블이 아니다. 스태틱 메서드 객체는 내장 staticmethod() 생성자로 만든다.

클래스 메서드 객체(Class method objects)

스태틱 메서드 객체처럼, 클래스 메서드 객체 역시 다른 객체를 둘러싸는데, 클래스와 클래스 인스턴스로부터 그 객체를 꺼내는 방식에 변화를 준다. 그런 조회에서 클래스 메서드 객체가 동작하는 방식에 대해서는 위 《사용자 정의 메서드(User-defined methods)》 에서 설명했다. 클래스 메서드 객체는 내장 classmethod() 생성자로 만든다.

3.3. 특수 메서드 이름들

클래스는 특별한 이름의 메서드들을 정의함으로써 특별한 문법 (산술 연산이나 인덱싱이나 슬라이딩 같은)에 의해 시작되는 어떤 연산들을 구현할 수 있다. 이것이 연산자 오버 로딩 (operator overloading)에 대한 파이썬의 접근법인데, 클래스가 언어의 연산자에 대해 자기 자신의 동작을 정의할 수 있도록 한다. 예를 들어, 클래스가 __getitem__() 이라는 이름의 메서드를 정의하고, x 가 이 클래스의 인스턴스라면, x[i] 는 대략 type(x).__getitem__(x, i) 와 동등하다. 언급된 경우를 제외하고, 적절한 메서드가 정의되지 않았을 때 연산은 예외를 일으킨다 (보통 AttributeErrorTypeError).

특수 메서드를 None 으로 설정하는 것은 해당 연산이 제공되지 않는다는 것을 가리킨다. 예를 들어, 만약 클래스가 __iter__()None 으로 설정하면, 클래스는 이터러블이 아니다. 따라서 이 인스턴스에 iter() 를 호출하면 TypeError 가 발생한다. (__getitem__() 을 대안으로 시도하지 않는다.) 2

내장형을 흉내 내는 클래스를 구현할 때, 모방은 모형화하는 객체에 말이 되는 수준까지만 구현하는 것이 중요하다. 예를 들어, 어떤 시퀀스는 개별 항목들을 꺼내는 것만으로도 잘 동작할 수 있다. 하지만 슬라이스를 꺼내는 것은 말이 안 될 수 있다. (이런 한가지 예는 W3C의 Document Object Model의 NodeList 인터페이스다.)

3.3.1. 기본적인 커스터마이제이션

object.__new__(cls[, ...])

클래스 cls 의 새 인스턴스를 만들기 위해 호출된다. __new__() 는 스태틱 메서드다 (그렇게 선언하지 않아도 되는 특별한 경우다)인데, 첫 번째 인자로 만들려고 하는 인스턴스의 클래스가 전달된다. 나머지 인자들은 객체 생성자 표현(클래스 호출)에 전달된 것들이다. __new__() 의 반환 값은 새 객체 인스턴스이어야 한다 (보통 cls 의 인스턴스).

일반적인 구현은 super().__new__(cls[, ...]) 에 적절한 인자들을 전달하는 방법으로 슈퍼 클래스의 __new__() 를 호출해서 새 인스턴스를 만든 후에, 돌려주기 전에 필요한 수정을 가한다.

만약 __new__()cls 의 인스턴스를 돌려준다면, 새 인스턴스의 __init__() 메서드가 __init__(self[, ...]) 처럼 호출되는데, self 는 새 인스턴스이고, 나머지 인자들은 __new__() 로 전달된 것들과 같다.

만약 __new__()cls 의 인스턴스를 돌려주지 않으면, 새 인스턴스의 __init__() 는 호출되지 않는다.

__new__() 는 주로 불변형(int, str, tuple과 같은)의 서브 클래스가 인스턴스 생성을 커스터마이즈할 수 있도록 하는 데 사용된다. 또한, 사용자 정의 메타 클래스에서 클래스 생성을 커스터마이즈하기 위해 자주 사용된다.

object.__init__(self[, ...])

(__new__() 에 의해) 인스턴스가 만들어진 후에, 하지만 호출자에게 돌려주기 전에 호출된다. 인자들은 클래스 생성자 표현으로 전달된 것들이다. 만약 베이스 클래스가 __init__() 메서드를 갖고 있다면, 서브 클래스의 __init__() 메서드는, 있다면, 인스턴스에서 베이스 클래스가 차지하는 부분이 올바르게 초기화됨을 확실히 하기 위해 명시적으로 호출해주어야 한다; 예를 들어: super().__init__([args...]).

객체를 만드는데 __new__()__init__() 가 협력하고 있으므로 (__new__() 는 만들고, __init__() 는 그것을 커스터마이즈한다), __init__()None 이외의 값을 돌려주면 실행시간에 TypeError 를 일으킨다.

object.__del__(self)

인스턴스가 파괴되기 직전에 호출된다. 파이널라이저 또는 (부적절하게) 파괴자라고 불린다. 만약 베이스 클래스가 __del__() 메서드를 갖고 있다면, 자식 클래스의 __del__() 메서드는, 정의되어 있다면, 인스턴스에서 베이스 클래스가 차지하는 부분을 적절하게 삭제하기 위해, 명시적으로 베이스 클래스의 메서드를 호출해야 한다.

(권장하지는 않지만!) __del__() 메서드는 인스턴스에 대한 새로운 참조를 만듦으로써 인스턴스의 파괴를 지연시킬 수 있다. 이것을 객체 부활 이라고 부른다. 부활한 객체가 파괴될 때 __del__() 이 두 번째로 호출될지는 구현에 따라 다르다; 현재 CPython 구현은 오직 한 번만 호출한다.

인터프리터가 종료할 때 아직 남아있는 객체들에 대해서는 __del__() 메서드의 호출이 보장되지 않는다.

참고

del x 는 직접 x.__del__() 를 호출하지 않는다 — 앞에 있는 것은 x 의 참조 횟수(reference count)를 하나 감소시키고, 뒤에 있는 것은 x 의 참조 횟수가 0 이 될 때 호출된다.

CPython implementation detail: It is possible for a reference cycle to prevent the reference count of an object from going to zero. In this case, the cycle will be later detected and deleted by the cyclic garbage collector. A common cause of reference cycles is when an exception has been caught in a local variable. The frame’s locals then reference the exception, which references its own traceback, which references the locals of all frames caught in the traceback.

더 보기

gc 모듈에 대한 문서.

경고

__del__() 이 호출되는 불안정한 상황 때문에, 이것이 실행 중에 발생시키는 예외는 무시되고, 대신에 sys.stderr 로 경고가 출력된다. 특히:

  • __del__() 은 (임의의 스레드에서) 임의의 코드가 실행되는 동안 호출될 수 있다. __del__() 이 록을 얻어야 하거나 다른 블로킹 자원을 호출하면, __del__() 을 실행하기 위해 중단된 코드가 자원을 이미 차지했을 수 있으므로 교착 상태에 빠질 수 있다.

  • __del__() 은 인터프리터를 종료할 때 실행될 수 있다. 결과적으로, 액세스해야 하는 전역 변수(다른 모듈 포함)가 이미 삭제되었거나 None 으로 설정되었을 수 있다. 파이썬은 이름이 하나의 밑줄로 시작하는 전역 객체가 다른 전역 객체들보다 먼저 삭제됨을 보장한다; 이것은, 만약 그 전역 객체들에 대한 다른 참조가 존재하지 않는다면, __del__() 메서드가 호출되는 시점에, 임포트된 모듈들이 남아있도록 확실히 하는 데 도움이 될 수 있다.

object.__repr__(self)

repr() 내장 함수에 의해 호출되어 객체의 《형식적인(official)》 문자열 표현을 계산한다. 만약 가능하다면, 이것은 같은 (적절한 환경이 주어질 때) 값을 갖는 객체를 새로 만들 수 있는 올바른 파이썬 표현식처럼 보여야 한다. 가능하지 않다면, <...쓸모있는 설명...> 형태의 문자열을 돌려줘야 한다. 반환 값은 반드시 문자열이어야 한다. 만약 클래스가 __str__() 없이 __repr__() 만 정의한다면, __repr__() 은 그 클래스 인스턴스의 《비형식적인(informal)》 문자열 표현이 요구될 때 사용될 수 있다.

이것은 디버깅에 사용되기 때문에, 표현이 풍부한 정보를 담고 모호하지 않게 하는 것이 중요하다.

object.__str__(self)

str(object) 와 내장 함수 format(), print() 에 의해 호출되어 객체의 《비형식적인(informal)》 또는 보기 좋게 인쇄 가능한 문자열 표현을 계산한다. 반환 값은 반드시 문자열 객체여야 한다.

이 메서드는 __str__() 이 올바른 파이썬 표현식을 돌려줄 것이라고 기대되지 않는다는 점에서 object.__repr__() 과 다르다: 더 편리하고 간결한 표현이 사용될 수 있다.

내장형 object 에 정의된 기본 구현은 object.__repr__() 을 호출한다.

object.__bytes__(self)

bytes 에 의해 호출되어 객체의 바이트열 표현을 계산한다. 반환 값은 반드시 bytes 객체여야 한다.

object.__format__(self, format_spec)

format() 내장 함수, 확대하면, 포맷 문자열 리터럴(formatted string literals) 의 계산과 str.format() 메서드에 의해 호출되어, 객체의 《포맷된》 문자열 표현을 만들어낸다. format_spec 인자는 요구되는 포맷 옵션들을 포함하는 문자열이다. format_spec 인자의 해석은 __format__() 을 구현하는 형에 달려있으나, 대부분 클래스는 포매팅을 내향형들의 하나로 위임하거나, 비슷한 포맷 옵션 문법을 사용한다.

표준 포매팅 문법에 대해서는 Format Specification Mini-Language 를 참고하면 된다.

반환 값은 반드시 문자열이어야 한다.

버전 3.4에서 변경: object 의 __format__ 메서드 자신은, 빈 문자열이 아닌 인자가 전달되면 TypeError 를 발생시킨다.

object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)

이것들은 소위 《풍부한 비교(rich comparison)》 메서드다. 연산자 기호와 메서드 이름 간의 관계는 다음과 같다: x<yx.__lt__(y) 를 호출한다, x<=yx.__le__(y) 를 호출한다, x==yx.__eq__(y) 를 호출한다, x!=yx.__ne__(y) 를 호출한다, x>yx.__gt__(y) 를 호출한다, x>=yx.__ge__(y) 를 호출한다.

풍부한 비교 메서드는 주어진 한 쌍의 인자에게 해당 연산을 구현하지 않는 경우 단일자(singleton) NotImplemented 를 돌려줄 수 있다. 관례상, 성공적인 비교면 FalseTrue 를 돌려준다. 하지만, 이 메서드는 어떤 형의 값이건 돌려줄 수 있다, 그래서 비교 연산자가 논리 문맥(Boolean context) (예를 들어 if 문의 조건)에서 사용되면, 파이썬은 결과의 참 거짓을 파악하기 위해 값에 대해 bool() 을 호출한다.

기본적으로, __ne__()__eq__() 를 호출한 후 NotImplemented 가 아니라면 그 결과를 뒤집는다. 비교 연산자 간의 다른 암시적인 관계는 없다. 예를 들어, (x<y or x==y) 가 참이라고 해서 x<=y 가 참일 필요는 없다. 하나의 기본 연산으로부터 대소관계 연산을 자동으로 만들어내려면 functools.total_ordering() 를 보면 된다.

사용자 정의 비교 연산자를 지원하고 딕셔너리 키로 사용될 수 있는 해시 가능 객체를 만드는 것에 관한 몇 가지 중요한 내용이 __hash__() 에 관한 문단에 나온다.

이 메서드들에 대한 (왼편의 인자는 연산을 지원하지 않지만, 오른편 인자가 지원할 때 사용되는) 뒤집힌 버전은 따로 없다; 대신에 __lt__()__gt__() 는 서로의 뒤집힌 연산이다; __le__()__ge__() 는 서로의 뒤집힌 연산이다; __eq__()__ne__() 는 서로의 뒤집힌 연산이다; 만약 피연산자가 서로 다른 형이고, 오른편 피연산자의 형이 왼편 피연산자의 형의 직간접적인 서브 클래스면, 오른편 피연산자의 뒤집힌 버전이 우선순위가 높다; 그렇지 않으면 왼편 피연산자의 메서드가 우선순위가 높다. 가상 서브클래싱(virtual subclassing)은 고려되지 않는다.

object.__hash__(self)

내장 함수 hash()set, frozenset, dict 와 같은 해시형 컬렉션의 멤버에 대한 연산에서 호출된다. __hash__() 는 정수를 돌려줘야 한다. 같다고 비교되는 객체들이 같은 해시값을 가져야 한다는 성질만 요구된다. 객체의 비교에 사용되는 요소들로 튜플을 구성하고, 그 튜플의 해시값을 취함으로써 요소들의 해시값을 섞는 것을 권한다. 예를 들면:

def __hash__(self):
    return hash((self.name, self.nick, self.color))

참고

hash() 는 객체가 정의한 __hash__() 메서드가 돌려주는 값을 Py_ssize_t 의 크기로 자른다(truncate). 이것은 보통 64-bit 빌드에서는 8바이트고, 32-bit 빌드에서는 4바이트다. 만약 객체의 __hash__() 가 서로 다른 비트 크기를 갖는 빌드들 사이에서 함께 사용되어야 한다면, 모든 지원할 빌드들에서의 폭을 검사해야 한다. 이렇게 하는 쉬운 방법은 python -c "import sys; print(sys.hash_info.width)" 이다.

만약 클래스가 __eq__() 를 정의하지 않으면 __hash__() 역시 정의하지 말아야 한다. 만약 __eq__() 를 정의하지만 __hash__() 를 정의하지 않는다면, 그것의 인스턴스는 해시 가능 컬렉션에서 사용될 수 없다. 만약 클래스가 가변형 객체를 정의하고 있고 __eq__() 를 구현한다면, __hash__() 를 구현하지 말아야 하는데, 해시 가능 컬렉션들의 구현이 키의 해시값이 불변이도록 요구하고 있기 때문이다(만약 객체의 해시값이 변하면, 잘못된 해시 버킷(hash bucket)에 있게 된다).

사용자 정의 클래스는 기본적으로 __eq__()__hash__() 메서드를 갖는다; 모든 객체는 (자기 자신을 제외하고) 같지 않다고 비교되고, x.__hash__() 는 적절한 값을 돌려주어, x == y 일 때 x is yhash(x) == hash(y) 가 동시에 성립할 수 있도록 한다.

__eq__() 를 재정의하고 __hash__() 를 정의하지 않는 클래스는 __hash__()None 으로 설정된다. 클래스의 __hash__() 메서드가 None 이면, 클래스의 인스턴스는 프로그램이 해시값을 얻으려 시도할 때 TypeError 를 일으키고, isinstance(obj, collections.Hashable) 로 검사할 때 해시 가능하지 않다고 올바로 감지된다.

만약 __eq__() 를 재정의하는 클래스가 부모 클래스로부터 __hash__() 의 구현을 물려받고 싶으면 인터프리터에게 명시적으로 이렇게 지정해주어야 한다: __hash__ = <ParentClass>.__hash__.

만약 __eq__() 를 재정의하지 않는 클래스가 해시 지원을 멈추고 싶으면, 클래스 정의에 __hash__ = None 을 포함해야 한다. 자신의 __hash__() 을 정의한 후에 직접 TypeError 를 일으키는 경우는 isinstance(obj, collections.Hashable) 호출이 해시 가능하다고 잘못 인식한다.

참고

기본적으로, str, bytes, datetime 객체들의 __hash__() 값은 예측할 수 없는 난수값으로 《솔트되어(salted)》 있다. 개별 파이썬 프로세스 내에서는 변하지 않는 값으로 유지되지만, 파이썬을 반복적으로 실행할 때는 예측할 수 없게 된다.

이것은 dict 삽입의 최악의 경우 성능(worst case performance), O(n^2) 복잡도, 을 활용하기 위해 주의 깊게 선택한 입력에 의한 서비스 거부(denial-of-service) 공격에 대한 방어를 제공하기 위한 목적이다. 자세한 내용은 http://www.ocert.org/advisories/ocert-2011-003.html 에 있다.

해시값의 변경은 딕셔너리와 집합과 그 밖의 다른 매핑들의 이터레이션 순서에 영향을 준다, 파이썬은 이 순서에 대해 어떤 보장도 하지 않는다 (그리고 보통 32-bit 와 64-bit 빌드 사이에서도 다르다).

PYTHONHASHSEED 를 참고하라.

버전 3.3에서 변경: 해시 난수 화는 기본적으로 활성화된다.

object.__bool__(self)

논리값 검사와 내장 연산 bool() 구현을 위해 호출된다; FalseTrue 를 돌려줘야 한다. 이 메서드가 정의되지 않는 경우, 정의되어 있다면 __len__() 이 호출되어, 값이 0 이 아니면 참으로 인식한다. 만약 클래스가 __len__()__bool__() 모두 정의하지 않는다면, 모든 인스턴스는 참으로 취급된다.

3.3.2. 어트리뷰트 액세스 커스터마이제이션

클래스 인스턴스의 어트리뷰트 참조(읽기, 대입하기, x.name 을 삭제하기)의 의미를 변경하기 위해 다음과 같은 메서드들이 정의될 수 있다.

object.__getattr__(self, name)

기본 어트리뷰트 액세스가 AttributeError 로 실패할 때 호출된다 (name 이 인스턴스 어트리뷰트 또는 self 의 클래스 트리에 있는 어트리뷰트가 아니라서 __getattribute__()AttributeError 를 일으키거나; name 프로퍼티의 __get__()AttributeError 를 일으킬 때). 이 메서드는 (계산된) 어트리뷰트 값을 반환하거나 AttributeError 예외를 일으켜야 한다.

일반적인 메커니즘을 통해 어트리뷰트가 발견되면 __getattr__() 이 호출되지 않음에 주의해야 한다 (이것은 __getattr__()__setattr__() 간의 의도된 비대칭이다). 이렇게 하는 이유는 효율 때문이기도 하고, 그렇게 하지 않으면 __getattr__() 가 인스턴스의 다른 어트리뷰트에 접근할 방법이 없기 때문이기도 하다. 적어도 인스턴스 변수의 경우, 어떤 값도 인스턴스 어트리뷰트 딕셔너리에 넣지 않음으로써 (대신에 그것들을 다른 객체에 넣는다) 완전한 제어인 것처럼 조작할 수 있다. 어트리뷰트 액세스를 실제로 완전히 조작하는 방법에 대해서는 아래에 나오는 __getattribute__() 에서 다룬다.

object.__getattribute__(self, name)

클래스 인스턴스의 어트리뷰트 액세스를 구현하기 위해 조건 없이 호출된다. 만약 클래스가 __getattr__() 도 함께 구현하면, __getattribute__() 가 명시적으로 호출하거나 AttributeError 를 일으키지 않는 이상 __getattr__ 는 호출되지 않는다. 이 메서드는 어트리뷰트의 (계산된) 값을 돌려주거나 AttributeError 예외를 일으켜야 한다. 이 메서드에서 무한 재귀(infinite recursion)가 발생하는 것을 막기 위해, 구현은 언제나 필요한 어트리뷰트에 접근하기 위해 같은 이름의 베이스 클래스의 메서드를 호출해야 한다. 예를 들어, object.__getattribute__(self, name).

참고

언어 문법이나 내장 함수에 의한 묵시적인 호출이 결과로 특수 메서드를 참조하는 경우에는 이 메서드를 거치지 않을 수 있다. 자세한 내용은 특수 메서드 조회 에서 다룬다.

object.__setattr__(self, name, value)

어트리뷰트 대입이 시도될 때 호출된다. 일반적인 메커니즘(즉 인스턴스 딕셔너리에 값을 저장하는 것) 대신에 이것이 호출된다. name 은 어트리뷰트 이름이고, value 는 그것에 대입하려는 값이다.

__setattr__() 에서 인스턴스 어트리뷰트에 대입하려고 할 때는, 같은 이름의 베이스 클래스의 메서드를 호출해야 한다. 예를 들어 object.__setattr__(self, name, value)

object.__delattr__(self, name)

__setattr__() 과 비슷하지만 어트리뷰트를 대입하는 대신에 삭제한다. 이것은 del obj.name 이 객체에 의미가 있는 경우에만 구현되어야 한다.

object.__dir__(self)

객체에 dir() 이 호출될 때 호출된다. 시퀀스를 돌려줘야 한다. dir() 은 돌려준 시퀀스를 리스트로 변환한 후 정렬한다.

3.3.2.1. 모듈 어트리뷰트 액세스 커스터마이제이션

모듈 동작(어트리뷰트 설정, 프로퍼티 등)을 보다 세밀하게 사용자 정의하려면, 모듈 객체의 __class__ 어트리뷰트를 types.ModuleType 의 서브 클래스로 설정할 수 있다. 예를 들면:

import sys
from types import ModuleType

class VerboseModule(ModuleType):
    def __repr__(self):
        return f'Verbose {self.__name__}'

    def __setattr__(self, attr, value):
        print(f'Setting {attr}...')
        setattr(self, attr, value)

sys.modules[__name__].__class__ = VerboseModule

참고

모듈 __class__ 설정은 어트리뷰트 액세스 구문을 사용하는 조회에만 영향을 미친다 – 모듈 전역에 대한 직접적인 액세스(모듈 내의 코드에 의한 액세스이거나 모듈의 전역 딕셔너리에 대한 참조를 통하거나)는 영향받지 않는다.

버전 3.5에서 변경: 이제 __class__ 모듈 어트리뷰트가 쓰기 가능하다.

3.3.2.2. 디스크립터 구현하기

다음에 오는 메서드들은 메서드를 가진 클래스(소위 디스크립터(descriptor) 클래스)의 인스턴스가 소유자(owner) 클래스에 등장할 때만 적용된다(디스크립터는 소유자 클래스의 딕셔너리나 그 부모 클래스 중 하나의 딕셔너리에 있어야 한다). 아래의 예에서, 《어트리뷰트》 는 이름이 소유자 클래스의 __dict__ 의 키로 사용되고 있는 어트리뷰트를 가리킨다.

object.__get__(self, instance, owner)

소유자 클래스(클래스 어트리뷰트 액세스) 나 그 클래스의 인스턴스(인스턴스 어트리뷰트 액세스)의 어트리뷰트를 취하려고 할 때 호출된다. owner 는 항상 소유자 클래스다. 반면에 instance 는 어트리뷰트 참조가 일어나고 있는 인스턴스이거나, 어트리뷰트가 owner 를 통해 액세스 되는 경우 None 이다. 이 메서드는 (계산된) 어트리뷰트 값을 돌려주거나 AttributeError 예외를 일으켜야 한다.

object.__set__(self, instance, value)

소유자 클래스의 인스턴스 instance 의 어트리뷰트를 새 값 value 로 설정할 때 호출된다.

object.__delete__(self, instance)

소유자 클래스의 인스턴스 instance 의 어트리뷰트를 삭제할 때 호출된다.

object.__set_name__(self, owner, name)

소유자 클래스 owner 가 만들어질 때 호출된다. 이 디스크립터가 name 에 대입되었다.

버전 3.6에 추가.

어트리뷰트 __objclass__inspect 모듈에 의해 이 객체가 정의된 클래스를 지정하는 것으로 해석된다(이 값을 적절히 설정하면 동적인 클래스 어트리뷰트의 실행시간 인트로스펙션(introspection)을 지원할 수 있다). 콜러블의 경우, 첫 번째 위치 인자에, 주어진 형(또는 서브 클래스)의 인스턴스가 기대되거나 요구됨을 가리킬 수 있다(예를 들어, CPython 은 C로 구현된 연결되지 않은 메서드(unbound method)에 이 어트리뷰트를 설정한다).

3.3.2.3. 디스크립터 호출하기

일반적으로, 디스크립터는 《결합한 동작(binding behavior)》을 가진 객체 어트리뷰트다. 어트리뷰트 액세스가 디스크립터 프로토콜(descriptor protocol)의 메서드들에 의해 재정의된다: __get__(), __set__(), __delete__(). 이 메서드들 중 하나라도 정의되어 있으면, 디스크립터라고 부른다.

어트리뷰트 액세스의 기본 동작은 객체의 딕셔너리에서 어트리뷰트를 읽고, 쓰고, 삭제하는 것이다. 예를 들어 a.xa.__dict__['x'] 에서 시작해서 type(a).__dict__['x'] 를 거쳐 type(a) 의 메타 클래스를 제외한 베이스 클래스들을 거쳐 가는 일련의 조회로 구성된다.

그러나, 만약 조회한 값이 디스크립터 메서드를 구현한 객체면, 파이썬은 기본 동작 대신에 디스크립터 메서드를 호출할 수 있다. 우선순위 목록의 어느 위치에서 이런 일이 일어나는지는 어떤 디스크립터 메서드가 정의되어 있고 어떤 식으로 호출되는지에 따라 다르다.

디스크립터 호출의 시작점은 결합(binding)이다, a.x. 어떻데 인자들이 조합되는지는 a 에 따라 다르다:

직접 호출

가장 간단하면서도 가장 덜 사용되는 호출은 사용자의 코드가 디스크립터 메서드를 직접 호출할 때다: x.__get__(a)

인스턴스 결합

객체 인스턴스에 결합하면, a.x 는 이런 호출로 변환된다: type(a).__dict__['x'].__get__(a, type(a)).

클래스 결합

클래스에 결합하면, A.x 는 이런 호출로 변환된다: A.__dict__['x'].__get__(None, A).

Super 결합

super 의 인스턴스에 결합하면, 결합 super(B, obj).m()obj.__class__.__mro__ 를 검색해서 B 바로 다음에 나오는 베이스 클래스 A 를 찾은 후에 이렇게 디스크립터를 호출한다: A.__dict__['m'].__get__(obj, obj.__class__).

인스턴스 결합의 경우, 디스크립터 호출의 우선순위는 어떤 디스크립터 메서드가 정의되어있는지에 따라 다르다. 디스크립터는 __get__(), __set__(), __delete__() 를 어떤 조합으로도 정의할 수 있다. 만약 __get__() 를 정의하지 않는다면, 어트리뷰트 액세스는, 객체의 인스턴스 딕셔너리에 값이 있지 않은 이상 디스크립터 객체 자신을 돌려준다. 만약 디스크립터가 __set__() 이나 __delete__() 중 어느 하나나 둘 다 정의하면, 데이터 디스크립터(data descriptor)다. 둘 다 정의하지 않는다면 비데이터 디스크립터다(non-data descriptor). 보통, 데이터 디스크립터가 __get__()__set__() 을 모두 정의하는 반면, 비데이터 디스크립터는 __get__() 메서드만 정의한다. __set__()__get__() 이 있는 데이터 디스크립터는 이스턴스 딕셔너리에 있는 값에 우선한다. 반면에 비데이터 디스크립터는 인스턴스보다 우선순위가 낮다.

파이썬 메서드 (staticmethod()classmethod() 를 포함해서) 는 비데이터 디스크립터로 구현된다. 이 때문에, 인스턴스는 메서드를 새로 정의하거나 덮어쓸 수 있다. 이것은 개별 인스턴스가 같은 클래스의 다른 인스턴스들과는 다른 동작을 얻을 수 있도록 만든다.

property() 함수는 데이터 디스크립터로 구현된다. 이 때문에, 인스턴스는 프로퍼티(property)의 동작을 변경할 수 없다.

3.3.2.4. __slots__

__slots__ 은 (프로퍼티처럼) 데이터 멤버를 명시적으로 선언하고 (__slots__ 에 명시적으로 선언하거나 부모로부터 물려받지 않는 한) __dict____weakref__ 생성을 거부할 수 있도록 한다.

__dict__ 를 사용할 때에 비교해 절약되는 공간은 상당할 수 있다.

object.__slots__

이 클래스 변수에는 인스턴스에 의해 사용되는 변수들의 이름을 제공하는 문자열, 이터러블(iterable), 문자열의 시퀀스가 대입될 수 있다. __slots__ 은 선언된 변수들을 위한 공간을 예약하고, 간 인스턴스마다 __dict____weakref__ 가 만들어지는 것을 막는다.

3.3.2.4.1. __slots__ 사용에 관한 노트
  • __slots__ 가 없는 클래스를 계승할 때, 인스턴스의 __dict____weakref__ 어트리뷰트는 항상 제공된다.

  • __dict__ 변수가 없으므로 인스턴스는 __slots__ 정의에 나열되지 않은 새 변수를 대입할 수 없다. 나열되지 않은 변수명으로 대입하려고 하면 AttributeError 를 일으킨다. 만약 동적으로 새 변수를 대입하는 것이 필요하다면, __slots__ 선언의 문자열 시퀀스에 '__dict__' 를 추가한다.

  • 인스턴스마다 __weakref__ 변수가 없으므로, __slots__ 를 정의하는 클래스는 인스턴스에 대한 약한 참조(weak reference)를 지원하지 않는다. 만약 약한 참조 지원이 필요하다면, __slots__ 선언의 문자열 시퀀스에 '__weakref__' 를 추가한다.

  • __slots__ 는 각 변수 이름마다 디스크립터를 만드는 방식으로 클래스 수준에서 구현된다(디스크립터 구현하기). 결과적으로, 클래스 어트리뷰트는 __slots__ 로 정의된 인스턴스 변수들을 위한 기본값을 제공할 목적으로 사용될 수 없다. 클래스 어트리뷰트는 디스크립터 대입을 무효로 한다.

  • __slots__ 선언으로 인한 효과는 그것이 정의된 클래스로 한정되지 않는다. 부모가 선언한 __slots__ 은 자식 클래스에 제공된다. 하지만, 자식 서브 클래스가 자신의 __slots__ (새로 추가되는 변수들만 포함해야 한다) 을 정의하지 않는다면 __dict____weakref__ 를 갖게 된다.

  • 클래스가 베이스 클래스의 __slots__ 에 정의된 이름과 같은 이름의 변수를 __slots__ 에 선언한다면, 베이스 클래스가 정의한 변수는 액세스할 수 없는 상태가 된다(베이스 클래스로부터 디스크립터를 직접 조회하는 경우는 예외다). 이것은 프로그램을 정의되지 않은 상태로 보내게 된다. 미래에는, 이를 방지하기 위한 검사가 추가될 것이다.

  • int, bytes, tuple 과 같은 《가변 길이(valiable-length)》 의 내장형들을 계승하는 클래스에서는 오직 빈 __slots__ 만 지원된다.

  • __slots__ 에는 문자열 이외의 이터러블을 대입할 수 있다. 매핑도 역시 사용할 수 있다. 하지만, 미래에, 각 키에 대응하는 값들의 의미가 부여될 수 있다.

  • 두 클래스가 같은 __slots__ 을 갖는 경우만 __class__ 대입이 동작한다.

  • 슬롯을 사용하는 여러 부모 클래스들을 다중 상속할 수 있지만, 오직 하나의 부모만 슬롯으로 만들어진 어트리뷰트를 가질 수 있다 (다른 베이스들은 빈 슬롯을 가져야만 한다) - 이를 어기면 TypeError 를 일으킨다.

3.3.3. 클래스 생성 커스터마이제이션

클래스가 다른 클래스를 상속할 때, 그 클래스의 __init_subclass__ 가 호출된다. 이 방법으로, 서브 클래스의 동작을 변경하는 클래스를 쓰는 것이 가능하다. 이런 용도는 클래스 데코레이터와도 밀접히 관련되어 있다. 하지만 클래스 데코레이터는 그들을 사용하는 특정한 클래스에만 작용하지만, __init_subclass__ 단독으로 그 메서드를 정의하는 클래스의 미래 서브 클래스 모두에게 작용한다.

classmethod object.__init_subclass__(cls)

이 메서드는 포함하는 클래스의 서브 클래스가 만들어질 때마다 호출된다. cls 는 새 서브 클래스다. 만약 일반적인 인스턴스 메서드로 정의되면, 이 메서드는 묵시적으로 클래스 메서드로 변경된다.

새 클래스에 주어진 키워드 인자들은 부모 클래스의 __init_subclass__ 로 전달된다. __init_subclass__ 를 사용하는 다른 클래스들과의 호환성을 위해, 필요한 키워드 인자들을 꺼낸 후에 다른 것들을 베이스 클래스로 전달해야 한다. 이런 식이다:

class Philosopher:
    def __init_subclass__(cls, default_name, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.default_name = default_name

class AustralianPhilosopher(Philosopher, default_name="Bruce"):
    pass

기본 구현 object.__init_subclass__ 는 아무 일도 하지 않지만, 인자가 포함되어 호출되면 예외를 발생시킨다.

참고

메타 클래스 힌트 metaclass 는 나머지 형 절차에 의해 소비되고, __init_subclass__ 로 전달되지 않는다. 실제 메타 클래스 (명시적인 힌트 대신에) 는 type(cls) 로 액세스할 수 있다.

버전 3.6에 추가.

3.3.3.1. 메타 클래스

기본적으로, 클래스는 type() 을 사용해서 만들어진다. 클래스의 바디는 새 이름 공간에서 실행되고, 클래스 이름은 type(name, bases, namespace) 의 결과에 지역적으로 연결된다.

클래스를 만드는 과정은 클래스 정의 줄에 metaclass 키워드 인자를 전달하거나, 그런 인자를 포함한 이미 존재하는 클래스를 계승함으로써 커스터마이즈될 수 있다. 다음 예에서, MyClassMySubclass 는 모두 Meta 의 인스턴스다.

class Meta(type):
    pass

class MyClass(metaclass=Meta):
    pass

class MySubclass(MyClass):
    pass

클래스 정의에서 지정된 다른 키워드 인자들은 아래에서 설명되는 모든 메타 클래스 연산들로 전달된다.

클래스 정의가 실행될 때, 다음과 같은 단계가 수행된다.:

  • 적절한 메타 클래스가 결정된다

  • 클래스 이름 공간이 준비된다

  • 클래스 바디가 실행된다

  • 클래스 객체가 만들어진다

3.3.3.2. 적절한 메타 클래스 선택하기

클래스 정의의 적절한 메타 클래스는 다음과 같이 결정된다:

  • 베이스와 명시적인 메타 클래스를 주지 않는 경우 type() 이 사용된다

  • 명시적인 메타 클래스가 지정되고, 그것이 type() 의 인스턴스가 아니면, 그것을 메타 클래스로 사용한다

  • type() 의 인스턴스가 명시적인 메타 클래스로 주어지거나, 베이스가 정의되었으면, 가장 많이 파생된 메타 클래스가 사용된다

가장 많이 파생된 메타 클래스는 명시적으로 지정된 메타 클래스(있다면)와 지정된 모든 베이스 클래스들의 메타 클래스들(즉, type(cls)) 중에서 선택된다. 가장 많이 파생된 메타 클래스는 이들 모두 의 서브 타입(subtype)이다. 만약 어느 것도 이 조건을 만족하지 못한다면, 클래스 정의는 TypeError 를 발생시키며 실패한다.

3.3.3.3. 클래스 이름 공간 준비하기

일단 적절한 메타 클래스가 식별되면, 클래스 이름 공간이 준비된다. 만약 메타 클래스가 __prepare__ 어트리뷰트를 가지면, namespace = metaclass.__prepare__(name, bases, **kwds) 같은 식으로 호출된다(추가적인 키워드 인자가 있다면 클래스 정의에서 온 것이다).

만약 메타 클래스에 __prepare__ 어트리뷰트가 없다면, 클래스 이름 공간은 빈 순서 있는 매핑(ordered mapping) 으로 초기화된다.

더 보기

PEP 3115 - 파이썬 3000 에서의 메타 클래스

__prepare__ 이름 공간 훅을 도입했다

3.3.3.4. 클래스 바디 실행하기

클래스 바디는 (대략) exec(body, globals(), namespace) 과같이 실행된다. 일반적인 exec() 호출과 주된 차이점은 클래스 정의가 함수 내부에서 이루어질 때 구문 스코핑(lexical scoping) 이 클래스 바디(모든 메서드들을 포함해서)로 하여금 현재와 외부 스코프에 있는 이름들을 참조하도록 허락한다는 것이다.

하지만, 클래스 정의가 함수 내부에서 이루어질 때조차도, 클래스 내부에서 정의된 메서드들은 클래스 스코프에서 정의된 이름들을 볼 수 없다. 클래스 변수는 인스턴스나 클래스 메서드의 첫 번째 파라미터를 통해 액세스하거나 다음 섹션에서 설명하는 묵시적으로 구문 스코핑된 __class__ 참조를 통해야 한다.

3.3.3.5. 클래스 객체 만들기

일단 클래스 이름 공간이 클래스 바디를 실행함으로써 채워지면, 클래스 객체가 metaclass(name, bases, namespace, **kwds) 을 통해 만들어진다(여기에서 전달되는 추가적인 키워드 인자들은 __prepare__ 에 전달된 것들과 같다).

이 클래스 객체는 super() 에 인자를 주지 않는 경우 참조되는 것이다. __class__ 는 클래스 바디의 메서드들 중 어느 하나라도 __class__super 를 참조할 경우 컴파일러에 의해 만들어지는 묵시적인 클로저(closure) 참조다. 이것은 인자 없는 형태의 super() 가 구문 스코핑 기반으로 현재 정의되고 있는 클래스를 올바르게 찾을 수 있도록 한다. 반면에 현재의 호출에 사용된 클래스나 인스턴스는 메서드로 전달된 첫 번째 인자에 기초해서 식별된다.

CPython implementation detail: CPython 3.6 이상에서, __class__ 셀(cell)은 클래스 이름 공간의 __classcell__ 엔트리로 메타 클래스에 전달된다. 만약 존재한다면, 이것은 클래스가 올바르게 초기화되기 위해 type.__new__ 호출까지 거슬러서 전파되어야 한다. 이렇게 하지 못하면 파이썬 3.6 에서는 DeprecationWarning으로, 파이썬 3.8 에서는 RuntimeError로 이어질 것이다.

기본 메타 클래스 type 을 사용할 때나 다른 메타 클래스가 결국 type.__new__ 를 호출할 때, 클래스 객체를 만든 후에, 다음과 같은 추가의 커스터마이제이션 단계가 실행된다:

  • 첫째로, type.__new____set_name__() 을 정의하는 클래스 이름 공간의 모든 디스크립터들을 수집한다;

  • 둘째로, 이렇게 수집된 모든 __set_name__ 을 호출하는데, 정의되고 있는 클래스와 디스크립터에 주어진 이름을 인자로 전달한다; 그리고

  • 마지막으로, 메서드 결정 순서에 따라 가장 가까운 부모에 대해 __init_subclass__() 훅 이 호출된다.

클래스 객체가 만들어진 후에, 클래스 정의에 포함된 클래스 데코레이터들에게 (있다면) 클래스를 전달하고, 그 결과를 클래스가 정의되는 지역 이름 공간에 연결한다.

type.__new__ 로 새 클래스가 만들어질 때, 이름 공간 파라미터로 제공되는 객체는 새로 만든 순서 있는 매핑으로 복사되고, 원래의 객체는 버린다. 새 사본은 읽기 전용 프락시(read-only proxy)로 둘러싸이는데, 이것이 클래스 객체의 __dict__ 어트리뷰트가 된다.

더 보기

PEP 3135 - 새 super

묵시적인 __class__ 클로저 참조를 설명한다

3.3.3.6. Uses for metaclasses

메타 클래스의 잠재적인 용도에는 한계가 없다. 탐색 된 몇 가지 아이디어들에는 enum, 로깅, 인터페이스 검사, 자동화된 위임(automatic delegation), 자동화된 프로퍼티(properety) 생성, 프락시(proxy), 프레임웍(framework), 자동화된 자원 로킹/동기화(automatic resource locking/synchronization) 등이 있다.

3.3.4. 인스턴스 및 서브 클래스 검사 커스터마이제이션

다음 메서드들은 isinstance()issubclass() 내장 함수들의 기본 동작을 재정의하는 데 사용된다.

특히, 메타 클래스 abc.ABCMeta 는 추상 베이스 클래스(Abstract Base Class, ABC)를 다른 ABC를 포함한 임의의 클래스나 형(내장형을 포함한다)에 《가상 베이스 클래스(virtual base class)》로 추가할 수 있게 하려고 이 메서드들을 구현한다.

class.__instancecheck__(self, instance)

instance 가 (직접적이거나 간접적으로) class 의 인스턴스로 취급될 수 있으면 참을 돌려준다. 만약 정의되면, isinstance(instance, class) 를 구현하기 위해 호출된다.

class.__subclasscheck__(self, subclass)

subclass 가 (직접적이거나 간접적으로) class 의 서브 클래스로 취급될 수 있으면 참을 돌려준다. 만약 정의되면, issubclass(subclass, class) 를 구현하기 위해 호출된다.

이 메서드들은 클래스의 형(메타 클래스)에서 조회된다는 것에 주의해야 한다. 실제 클래스에서 클래스 메서드로 정의될 수 없다. 이것은 인스턴스에 대해 호출되는 특수 메서드들의 조회와 일관성 있다. 이 경우 인스턴스는 클래스 자체다.

더 보기

PEP 3119 - 추상 베이스 클래스의 도입

__instancecheck__()__subclasscheck__() 를 통해 isinstance()issubclass() 의 동작을 커스터마이징하는 데 필요한 규약을 포함하는데, 이 기능의 동기는 언어에 추상 베이스 클래스 (abc 모듈을 보라)를 추가하고자 하는 데 있다.

3.3.5. 콜러블 객체 흉내 내기

object.__call__(self[, args...])

인스턴스가 함수처럼 《호출될》 때 호출된다; 이 메서드가 정의되면, x(arg1, arg2, ...)x.__call__(arg1, arg2, ...) 의 줄인 표현이다.

3.3.6. 컨테이너형 흉내 내기

컨테이너 객체를 구현하기 위해 다음과 같은 메서드들을 정의할 수 있다. 컨테이너는 보통 시퀀스(리스트와 튜플 같은)나 매핑(딕셔너리 같은)이지만, 다른 컨테이너들 역시 표현할 수 있다. 첫 번째 메서드 집합은 시퀀스나 매핑을 흉내 내는 데 사용된다; 차이점은, 시퀀스의 경우 허락되는 키는 N 이 시퀀스의 길이일 때 0 <= k < N 를 만족하는 정수 k 와 항목들의 범위를 정의하는 슬라이스 객체만 허락된다는 것이다. 파이썬의 표준 딕셔너리 객체와 비슷하게 동작하도록, 매핑에 메서드 keys(), values(), items(), get(), clear(), setdefault(), pop(), popitem(), copy(), update() 를 제공하는 것이 좋다. collections 모듈은 MutableMapping 추상 베이스 클래스를 제공하는데, 기본 집합 __getitem__(), __setitem__(), __delitem__(), keys() 로 부터 이들 메서드들을 만드는 데 도움을 준다. 파이썬의 표준 리스트 객체처럼, 가변 시퀀스는 메서드 append(), count(), index(), extend(), insert(), pop(), remove(), reverse(), sort() 를 제공해야 한다. 마지막으로 시퀀스 형은 아래에서 설명하는 메서드 __add__(), __radd__(), __iadd__(), __mul__(), __rmul__(), __imul__() 를 정의해서 더하기(이어붙이기를 뜻한다)와 곱하기(반복을 뜻한다)를 구현해야 한다. 다른 숫자 연산자들은 정의하지 말아야 한다. in 연산자의 효과적인 사용을 허락하기 위해, 매핑과 시퀀스 모두 __contains__() 메서드를 구현하도록 권장한다. 매핑의 경우, in 은 매핑의 키를 검색해야 한다; 시퀀스의 경우, 값들을 검색해야 한다. 컨테이너의 효율적인 이터레이션을 허락하기 위해, 매핑과 시퀀스 모두 __iter__() 메서드를 구현하는 것 또한 권장한다; 매핑의 경우, __iter__()keys() 와 같아야 한다; 시퀀스의 경우, 값들을 이터레이트해야 한다.

object.__len__(self)

내장함수 len() 를 구현하기 위해 호출된다. 객체의 길이를 돌려줘야 하는데, >= 0인 정수다. 또한 __bool__() 메서드를 정의하지 않은 객체의 __len__() 이 0을 돌려주면 논리 문맥에서 거짓으로 취급된다.

CPython implementation detail: CPython 에서, 길이는 최대 sys.maxsize 일 것이 요구된다. 만약 길이가 sys.maxsize 보다 크면, 어떤 기능들 (len() 과 같은)은 OverflowError 를 일으킬 수 있다. 참 거짓 검사에서 OverflowError 가 일어나는 것을 막기 위해, 객체는 __bool__() 를 정의해야 한다.

object.__length_hint__(self)

operator.length_hint() 를 구현하기 위해 호출된다. 객체의 추정된 길이를 돌려줘야 한다(실제 길이보다 크거나 작을 수 있다). 길이는 >= 0인 정수여야 한다. 이 메서드는 순수하게 최적화를 위한 것이고 결코 올바름이 요구되지는 않는다.

버전 3.4에 추가.

참고

슬라이싱은 전적으로 다음에 나오는 세 메서드들에의해 수행된다

a[1:2] = b

과 같은 호출은

a[slice(1, 2, None)] = b

로 번역되고, 다른 형태도 마찬가지다. 빠진 슬라이스 항목은 항상 None 으로 채워진다.

object.__getitem__(self, key)

self[key] 의 값을 구하기 위해 호출된다. 시퀀스형의 경우, 정수와 슬라이스 객체만 키로 허용된다. 음수 인덱스(만약 클래스가 시퀀스 형을 흉내 내길 원한다면)의 특별한 해석은 __getitem__() 메서드에 달려있음에 주의해야 한다. 만약 key 가 적절하지 않은 형인 경우, TypeError 가 발생할 수 있다; 만약 시퀀스의 인덱스 범위를 벗어나면(음수에 대한 특별한 해석 후에), IndexError 를 일으켜야 한다. 매핑 형의 경우, key 가 (컨테이너에) 없으면, KeyError 를 일으켜야 한다.

참고

for 루프는 시퀀스의 끝을 올바로 감지하기 위해, 잘못된 인덱스에 대해 IndexError 가 일어날 것으로 기대하고 있다.

object.__setitem__(self, key, value)

self[key] 로의 대입을 구현하기 위해 호출된다. __getitem__() 과 같은 주의가 필요하다. 매핑의 경우에는, 객체가 키에 대해 값의 변경이나 새 키의 추가를 허락할 경우, 시퀀스의 경우는 항목이 교체될 수 있을 때만 구현되어야 한다. 잘못된 key 값의 경우는 __getitem__() 에서와 같은 예외를 일으켜야 한다.

object.__delitem__(self, key)

self[key] 의 삭제를 구현하기 위해 호출된다. __getitem__() 과 같은 주의가 필요하다. 매핑의 경우에는, 객체가 키의 삭제를 허락할 경우, 시퀀스의 경우는 항목이 시퀀스로부터 제거될 수 있을 때만 구현되어야 한다. 잘못된 key 값의 경우는 __getitem__() 에서와 같은 예외를 일으켜야 한다.

object.__missing__(self, key)

dict.__getitem__() 이 dict 서브 클래스에서 키가 딕셔너리에 없으면 self[key] 를 구현하기 위해 호출한다.

object.__iter__(self)

컨테이너의 이터레이터가 필요할 때 이 메서드가 호출된다. 이 메서드는 컨테이너에 포함된 모든 객체를 이터레이트할 수 있는 이터레이터 객체를 돌려줘야 한다. 매핑의 경우, 컨테이너의 키를 이터레이트해야 한다.

이터레이터 객체 역시 이 메서드를 구현할 필요가 있다; 자기 자신을 돌려줘야 한다. 이터레이터 객체에 대한 추가의 정보는 이터레이터 형 에 있다.

object.__reversed__(self)

reversed() 내장 함수가 역 이터레이션(reverse iteration)을 구현하기 위해 (있다면) 호출한다. 컨테이너에 있는 객체들을 역 순으로 탐색하는 새 이터레이터 객체를 돌려줘야 한다.

__reversed__() 메서드가 제공되지 않으면, reversed() 내장함수는 시퀀스 프로토콜(__len__()__getitem__())을 대안으로 사용한다. 시퀀스 프로토콜을 지원하는 객체들은 reversed() 가 제공하는 것보다 더 효율적인 구현을 제공할 수 있을 때만 __reversed__() 를 제공해야 한다.

멤버십 검사 연산자들(innot in) 은 보통 시퀀스에 대한 이터레이션으로 구현된다. 하지만, 컨테이너 객체는 더 효율적인 구현을 다음과 같은 특수 메서드를 통해 제공할 수 있다. 이 경우 객체는 시퀀스일 필요도 없다.

object.__contains__(self, item)

멤버십 검사 연산자를 구현하기 위해 호출된다. itemself 에 있으면 참을, 그렇지 않으면 거짓을 돌려줘야 한다. 매핑 객체의 경우, 키-값 쌍이 아니라 매핑의 키가 고려되어야 한다.

__contains__() 를 정의하지 않는 객체의 경우, 멤버십 검사는 먼저 __iter__() 를 통한 이터레이션을 시도한 후, __getitem__() 을 통한 낡은 시퀀스 이터레이션 프로토콜을 시도한다. membership-test-details 섹션을 참고하라.

3.3.7. 숫자 형 흉내 내기

숫자 형을 흉내 내기 위해 다음과 같은 메서드들을 정의할 수 있다. 구현되는 특별한 종류의 숫자에 의해 지원되지 않는 연산들(예를 들어, 정수가 아닌 숫자들에 대한 비트 연산들)에 대응하는 메서드들을 정의되지 않은 채로 남겨두어야 한다.

object.__add__(self, other)
object.__sub__(self, other)
object.__mul__(self, other)
object.__matmul__(self, other)
object.__truediv__(self, other)
object.__floordiv__(self, other)
object.__mod__(self, other)
object.__divmod__(self, other)
object.__pow__(self, other[, modulo])
object.__lshift__(self, other)
object.__rshift__(self, other)
object.__and__(self, other)
object.__xor__(self, other)
object.__or__(self, other)

이 메서드들은 이항 산술 연산들(+, -, *, @, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |)을 구현하기 위해 호출된다. 예를 들어, x__add__() 메서드를 가진 클래스의 인스턴스일 때, 표현식 x + y 의 값을 구하기 위해, x.__add__(y) 가 호출된다. __divmod__() 메서드는 __floordiv__()__mod__() 를 사용하는 것과 동등해야 한다; __truediv__() 와 연관되지 않아야 한다; 내장 pow() 함수의 삼 항 버전이 지원되기 위해서는, __pow__() 메서드가 생략할 수 있는 세 번째 인자를 받도록 정의되어야 함에 주의해야 한다.

만약 이 메서드들 중 하나가 제공된 인자에 대해 연산을 지원하지 않으면, NotImplemented 를 돌려줘야 한다.

object.__radd__(self, other)
object.__rsub__(self, other)
object.__rmul__(self, other)
object.__rmatmul__(self, other)
object.__rtruediv__(self, other)
object.__rfloordiv__(self, other)
object.__rmod__(self, other)
object.__rdivmod__(self, other)
object.__rpow__(self, other)
object.__rlshift__(self, other)
object.__rrshift__(self, other)
object.__rand__(self, other)
object.__rxor__(self, other)
object.__ror__(self, other)

이 메서드들은 뒤집힌 피연산자들에 대해 이항 산술 연산들(+, -, *, @, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |)을 구현하기 위해 호출된다. 이 함수들은 왼쪽의 피연산자가 해당 연산을 지원하지 않고 3, 피연산자들이 서로 다른 형일 때만 호출된다. 4 예를 들어, 표현식 x - y 의 값을 구하려고 할 때, y__rsub__() 를 갖는 클래스의 인스턴스이고, x.__sub__(y)NotImplemented 를 돌려주면 y.__rsub__(x) 가 호출된다.

삼 항 pow()__rpow__() 를 호출하려고 시도하지 않음에 주의해야 한다 (그렇게 하려면 코어션 규칙이 너무 복잡해진다).

참고

만약 오른쪽 피연산자의 형이 왼쪽 피연산자의 형의 서브 클래스이고, 그 서브 클래스가 연산의 뒤집힌 메서드들 제공하면, 이 메서드가 왼쪽 연산자의 뒤집히지 않은 메서드보다 먼저 호출된다. 이 동작은 서브 클래스가 조상들의 연산을 재정의할 수 있도록 한다.

object.__iadd__(self, other)
object.__isub__(self, other)
object.__imul__(self, other)
object.__imatmul__(self, other)
object.__itruediv__(self, other)
object.__ifloordiv__(self, other)
object.__imod__(self, other)
object.__ipow__(self, other[, modulo])
object.__ilshift__(self, other)
object.__irshift__(self, other)
object.__iand__(self, other)
object.__ixor__(self, other)
object.__ior__(self, other)

이 메서드들은 증분 산술 대입(+=, -=, *=, @=, /=, //=, %=, **=, <<=, >>=, &=, ^=, |=)을 구현하기 위해 호출된다. 이 메서드는 연산을 제자리에서(self 를 수정해서) 하도록 시도해야 하고, 결과(반드시 그래야 하는 것은 아니지만 self 일 수 있다)를 돌려줘야 한다. 만약 특정 메서드가 정의되지 않으면, 중분 대입은 일반적인 메서드들을 대신 사용한다. 예를 들어, x__iadd__() 메서드를 갖는 클래스의 인스턴스면, x += yx = x.__iadd__(y) 와 동등하다. 그렇지 않으면, x + y 의 값을 구할 때처럼, x.__add__(y)y.__radd__(x) 가 고려된다. 어떤 상황에서, 증분 대입은 예상치 못한 에러로 이어질 수 있다. (Why does a_tuple[i] += [〈item〉] raise an exception when the addition works? 를 보라). 하지만 이 동작은 사실 데이터 모델의 일부다.

object.__neg__(self)
object.__pos__(self)
object.__abs__(self)
object.__invert__(self)

일 항 산술 연산(-, +, abs(), ~)을 구현하기 위해 호출된다.

object.__complex__(self)
object.__int__(self)
object.__float__(self)

내장 함수 complex(), int(), float()를 구현하기 위해 호출된다. 적절한 형의 값을 돌려줘야 한다.

object.__index__(self)

operator.index() 를 구현하기 위해 호출되고, 파이썬이 숫자 객체를 정수 객체로 손실 없이 변환해야 할 때(슬라이싱이나 내장 bin(), hex(), oct() 함수들에서와같이)마다 호출된다. 이 메서드의 존재는 숫자 객체가 정수 형임을 가리킨다. 반드시 정수를 돌려줘야 한다.

참고

일관성 있는 정수형 클래스를 가지려고, __index__() 가 정의될 때는 __int__() 역시 정의되어야 하고, 둘 다 같은 값을 돌려줘야 한다.

object.__round__(self[, ndigits])
object.__trunc__(self)
object.__floor__(self)
object.__ceil__(self)

내장 함수 round()math 함수 trunc(), floor(), ceil() 을 구현하기 위해 호출된다. ndigits__round__() 로 전달되지 않는 한, 이 메서드들은 모두 Integral (보통 int) 로 잘린 객체의 값을 돌려줘야 한다.

__int__() 가 정의되어 있지 않으면, 내장 함수 int()__trunc__() 를 사용한다.

3.3.8. with 문 컨텍스트 관리자

컨텍스트 관리자 (context manager)with 문을 실행할 때 자리 잡는 실행 컨텍스트(context)를 정의하는 객체다. 코드 블록의 실행을 위해, 컨텍스트 관리자는 원하는 실행시간 컨텍스트로의 진입과 탈출을 처리한다. 컨텍스트 관리자는 보통 with 문(with 문 섹션에서 설명한다)으로 시작되지만, 그들의 메서드를 호출해서 직접 사용할 수도 있다.

컨텍스트 관리자의 전형적인 용도에는 다양한 종류의 전역 상태(global state)를 보관하고 복구하는 것, 자원을 로킹(locking)하고 언로킹(unlocking)하는 것, 열린 파일을 닫는 것 등이 있다.

컨텍스트 관리자에 대한 더 자세한 정보는 컨텍스트 관리자 형 에 나온다.

object.__enter__(self)

이 객체와 연관된 실행시간 컨텍스트에 진입한다. with 문은 as 절로 지정된 대상이 있다면, 이 메서드의 반환 값을 연결한다.

object.__exit__(self, exc_type, exc_value, traceback)

이 객체와 연관된 실행시간 컨텍스트를 종료한다. 파라미터들은 컨텍스트에서 벗어나게 만든 예외를 기술한다. 만약 컨텍스트가 예외 없이 종료한다면, 세 인자 모두 None 이 된다.

만약 예외가 제공되고, 메서드가 예외를 중지시키고 싶으면 (즉 확산하는 것을 막으려면) 참(true)을 돌려줘야 한다. 그렇지 않으면 예외는 이 메서드가 종료한 후에 계속 진행된다.

__exit__() 메서드가 전달된 예외를 다시 일으키지(reraise) 않도록 주의해야 한다; 이것은 호출자(caller)의 책임이다.

더 보기

PEP 343 - 《with》 문

파이썬 with 문에 대한 규격, 배경, 예.

3.3.9. 특수 메서드 조회

사용자 정의 클래스의 경우, 묵시적인 특수 메서드의 호출은 객체의 인스턴스 딕셔너리가 아닌 객체의 형에 정의되어 있을 때만 올바르게 동작함이 보장된다. 이런 동작은 다음과 같은 코드가 예외를 일으키는 원인이다:

>>> class C:
...     pass
...
>>> c = C()
>>> c.__len__ = lambda: 5
>>> len(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'C' has no len()

이런 동작의 배경에 깔린 논리는, 모든 객체(형 객체를 포함해서)들에 의해 구현되는 __hash__()__repr__() 과 같은 많은 특수 메서드들과 관련이 있다. 만약 이 메서드들에 대한 묵시적인 조회가 일반적인 조회 프로세스를 거친다면, 형 객체 자체에 대해 호출되었을 때 실패하게 된다:

>>> 1 .__hash__() == hash(1)
True
>>> int.__hash__() == hash(int)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor '__hash__' of 'int' object needs an argument

클래스의 연결되지 않은 메서드를 호출하려는 이런 식의 잘못된 시도는 종종 〈메타 클래스 혼란(metaclass confusion)〉 이라고 불리고, 특수 메서드를 조회할 때 인스턴스를 우회하는 방법으로 피할 수 있다.

>>> type(1).__hash__(1) == hash(1)
True
>>> type(int).__hash__(int) == hash(int)
True

올바름을 추구하기 위해 인스턴스 어트리뷰트들을 우회하는 것에 더해, 묵시적인 특수 메서드 조회는 객체의 메타 클래스의 __getattribute__() 메서드 조차도 우회한다:

>>> class Meta(type):
...     def __getattribute__(*args):
...         print("Metaclass getattribute invoked")
...         return type.__getattribute__(*args)
...
>>> class C(object, metaclass=Meta):
...     def __len__(self):
...         return 10
...     def __getattribute__(*args):
...         print("Class getattribute invoked")
...         return object.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__()                 # Explicit lookup via instance
Class getattribute invoked
10
>>> type(c).__len__(c)          # Explicit lookup via type
Metaclass getattribute invoked
10
>>> len(c)                      # Implicit lookup
10

이런 식으로 __getattribute__() 절차를 우회하는 것은 특수 메서드 처리의 유연함을 일부 포기하는 대신(특수 메서드가 인터프리터에 의해 일관성 있게 호출되기 위해서는 반드시 클래스 객체에 설정되어야 한다), 인터프리터 내부에서의 속도 최적화를 위한 상당한 기회를 제공한다.

3.4. 코루틴(Coroutines)

3.4.1. 어웨이터블 객체(Awaitable Objects)

어웨이터블 객체는 일반적으로 __await__() 메서드를 구현한다. async def 함수가 돌려주는 코루틴 객체는 어웨이터블이다.

참고

types.coroutine() 이나 asyncio.coroutine() 로 데코레이션된 제너레이터가 돌려주는 제너레이터 이터레이터 객체 또한 어웨이터블이지만 __await__() 를 구현하지 않는다.

object.__await__(self)

이터레이터 를 돌려줘야 한다. 어웨이터블 객체를 구현하기 위해 사용되어야 한다. 예를 들어, asyncio.Futureawait 표현식과 호환되기 위해 이 메서드를 구현한다.

버전 3.5에 추가.

더 보기

PEP 492 가 어웨이터블 객체에 대한 더 자세한 정보를 포함하고 있다.

3.4.2. 코루틴 객체(Coroutine Objects)

코루틴 객체는 어웨이터블 객체다. 코루틴의 실행은 __await__() 를 호출하고 그 결과를 이터레이트하는 방법으로 제어될 수 있다. 코루틴이 실행을 완료하고 복귀할 때, 이터레이터는 StopIteration 을 일으키고, 예외의 value 어트리뷰트가 반환 값을 갖고 있다. 만약 코루틴이 예외를 일으키면, 이터레이터에 의해 퍼진다. 코루틴이 직접 잡히지 않은 StopIteration 예외를 일으키지는 말아야 한다.

코루틴은 다음에 나열하는 메서드들 또한 갖고 있는데, 제너레이터(제너레이터-이터레이터 메서드 를 보라)의 것들과 닮았다. 하지만, 제너레이터와는 달리, 코루틴은 이터레이션을 직접 지원하지는 않는다.

버전 3.5.2에서 변경: 코루틴을 두 번 await 하면 RuntimeError 를 일으킨다.

coroutine.send(value)

코루틴의 실행을 시작하거나 재개한다. valueNone 이면, __await__() 가 돌려준 이터레이터를 전진시키는 것과 같다. valueNone 이 아니면, 이 메서드는 코루틴이 일시 중지되도록 한 이터레이터의 send() 메서드로 위임한다. 결과(반환 값, StopIteration 이나 다른 예외)는 위에서 설명한 __await__() 의 반환 값을 이터레이트할 때와 같다.

coroutine.throw(type[, value[, traceback]])

코루틴에서 지정한 예외가 발생하도록 한다. 이 메서드는 코루틴이 일시 중지되도록 한 이터레이터의 throw() 메서드로 위임한다(그런 메서드를 가지는 경우). 그렇지 않으면, 일시 중지지점에서 예외가 발생한다. 결과(반환 값, StopIteration 이나 다른 예외)는 위에서 설명한 __await__() 의 반환 값을 이터레이트할 때와 같다. 만약 예외가 코루틴에서 잡히지 않는다면 호출자에게 되돌아 전파된다.

coroutine.close()

코루틴이 자신을 정리하고 종료하도록 만든다. 만약 코루틴이 일시 중지 중이면, 이 메서드는 먼저 코루틴이 일시 중지되도록 한 이터레이터의 close() 메서드로 위임한다(그런 메서드를 가지는 경우). 그런 다음 일시 중지지점에서 GeneratorExit 를 발생시키는데, 코루틴이 즉시 자신을 정리하도록 만든다. 마지막으로 코루틴에 실행을 종료했다고 표시하는데, 아직 시작하지조차 않았을 때도 그렇다.

코루틴 객체가 파괴될 때는 위의 프로세스에 따라 자동으로 닫힌다(closed).

3.4.3. 비동기 이터레이터(Asynchronous Iterators)

비동기 이터러블(asynchronous iterable) 은 자신의 __aiter__ 구현에서 비동기 코드를 호출할 수 있고, 비동기 이터레이터 는 자신의 __anext__ 메서드에서 비동기 코드를 호출할 수 있다.

비동기 이터레이터는 async for 문에서 사용될 수 있다.

object.__aiter__(self)

비동기 이터레이터 객체를 돌려줘야 한다.

object.__anext__(self)

이터레이터의 다음 값을 주는 어웨이터블 을 돌려줘야 한다. 이터레이션이 끝나면 StopAsyncIteration 에러를 일으켜야 한다.

비동기 이터러블 객체의 예:

class Reader:
    async def readline(self):
        ...

    def __aiter__(self):
        return self

    async def __anext__(self):
        val = await self.readline()
        if val == b'':
            raise StopAsyncIteration
        return val

버전 3.5에 추가.

참고

버전 3.5.2에서 변경: CPython 3.5.2부터, __aiter__비동기 이터레이터 를 직접 돌려줄 수 있다. 어웨이터블 객체를 돌려주면 PendingDeprecationWarning 이 발생한다.

CPython 3.5.x 와의 과거 호환성을 유지하는 코드들 작성을 위해 권장하는 방법은 __aiter__ 에서 계속 어웨이터블을 돌려주는 것이다. 만약 PendingDeprecationWarning 를 피하면서 코드의 과거 호환성을 유지하고 싶다면, 다음과 같은 데코레이터를 사용할 수 있다:

import functools
import sys

if sys.version_info < (3, 5, 2):
    def aiter_compat(func):
        @functools.wraps(func)
        async def wrapper(self):
            return func(self)
        return wrapper
else:
    def aiter_compat(func):
        return func

예:

class AsyncIterator:

    @aiter_compat
    def __aiter__(self):
        return self

    async def __anext__(self):
        ...

CPython 3.6부터, PendingDeprecationWarningDeprecationWarning으로 변경되었다. CPython 3.7부터, __aiter__ 이 어웨이터블을 돌려주면 RuntimeError 을 일으킬 것이다.

3.4.4. 비동기 컨텍스트 관리자

비동기 컨텍스트 관리자(asynchronous context manager)__aenter____aexit__ 메서드에서 실행을 일시 중지할 수 있는 컨텍스트 관리자 다.

비동기 컨텍스트 관리자는 async with 문에서 사용될 수 있다.

object.__aenter__(self)

이 메서드는 __enter__() 메서드와 의미상으로 유사한데, 유일한 차이점은 어웨이터블 을 돌려줘야 한다는 것이다.

object.__aexit__(self, exc_type, exc_value, traceback)

이 메서드는 __exit__() 메서드와 의미상으로 유사한데, 유일한 차이점은 어웨이터블 을 돌려줘야 한다는 것이다.

비동기 컨텍스트 관리자 클래스의 예:

class AsyncContextManager:
    async def __aenter__(self):
        await log('entering context')

    async def __aexit__(self, exc_type, exc, tb):
        await log('exiting context')

버전 3.5에 추가.

각주

1

어떤 제한된 조건으로, 어떤 경우에 객체의 형을 변경하는 것이 가능하다. 하지만 잘못 다뤄지면 아주 괴상한 결과로 이어질 수 있으므로 일반적으로 좋은 생각이 아니다.

2

__hash__(), __iter__(), __reversed__(), __contains__() 메서드들이 이런 경우에 대한 특별한 처리를 포함하고 있다; 다른 것들도 여전히 TypeError 을 일으키지만, 단지 None 이 콜러블이 아니므로 그런 것뿐이다.

3

여기서 《지원하지 않는다》 는 클래스가 그런 메서드를 갖지 않거나, 메서드가 NotImplemented 를 돌려줌을 뜻한다. 오른쪽 피연산자의 뒤집힌 메서드를 사용하는 대안이 시도되도록 하려면 메서드를 None 으로 설정하지 말아야 한다 - 그렇게 하는 것은 그런 대안을 명시적으로 금지하는 반대 효과를 준다.

4

피연산자들이 같은 형이면, 뒤집히지 않은 메서드(__add__() 같은)가 실패하면 그 연산이 지원되지 않는 것으로 간주한다. 이것이 뒤집힌 메서드가 호출되지 않는 이유다.