3. 데이터 모델
3. 데이터 모델 (Data model)
이 장에서는 객체, 값, 타입이 무엇인지, 그리고 Python이 언제 어떤 객체를 만들고 파괴하는지, 특수 메서드(special method) 이름이 어떻게 정의되는지, 그리고 비동기·동기 코루틴의 모델을 설명합니다.
출처: 3. Data model
본문
3.1. 객체, 값과 타입 (Objects, values and types)
*객체(objects)*는 데이터에 대한 Python의 추상화예요. Python 프로그램의 모든 데이터는 객체 또는 객체 간의 관계로 표현됩니다. 심지어 코드도 객체로 표현돼요.
모든 객체는 정체성(identity), 타입(type), 값(value)을 가집니다. 객체의 정체성은 생성된 후 절대 변하지 않습니다. 메모리에서 객체의 주소라고 생각하면 돼요. is 연산자는 두 객체의 정체성을 비교합니다. id() 함수는 정체성을 나타내는 정수를 반환합니다.
CPython implementation detail: CPython에서 id(x)는 x가 저장된 메모리 주소입니다.
객체의 타입은 객체가 지원하는 연산(예: "길이가 있나?")을 결정하고, 그 타입의 객체가 가질 수 있는 값도 정의합니다. type() 함수는 객체의 타입을 반환합니다(그 자체가 객체). 정체성처럼 객체의 타입도 변경할 수 없어요. [1]
일부 객체의 값은 변경될 수 있습니다. 값이 변경될 수 있는 객체를 *변경 가능(mutable)*하다고 하고, 생성된 후 값이 변경되지 않는 객체를 *불변(immutable)*이라고 합니다. (변경 가능한 객체에 대한 참조를 포함하는 불변 컨테이너 객체의 값은 후자가 변경되면 바뀔 수 있어요. 하지만 컨테이너가 포함하는 객체들의 집합은 변경할 수 없으므로 여전히 불변으로 간주됩니다. 따라서 불변성은 엄밀히 말해 변경할 수 없는 값과 같지 않으며, 더 미묘합니다.) 객체의 변경 가능성은 타입에 의해 결정되며, 예를 들어 숫자, 문자열, 튜플은 불변이고 딕셔너리와 리스트는 변경 가능합니다.
객체는 명시적으로 파괴되지 않지만, 도달 불가능(unreachable)해지면 가비지 컬렉션될 수 있어요. 구현은 가비지 컬렉션을 연기하거나 아예 생략할 수 있습니다. 아직 도달 가능한 객체를 수집하지 않는 한, 가비지 컬렉션을 어떻게 구현하는지는 구현 품질의 문제입니다.
CPython implementation detail: CPython은 현재 (선택적인) 순환 연결 가비지 지연 감지와 함께 참조 계수(reference-counting) 방식을 사용하며, 대부분의 객체를 도달 불가능해지면 바로 수집하지만 순환 참조를 포함하는 가비지를 수집하리라는 보장은 없습니다. 순환 가비지 수집 제어에 대한 정보는 gc 모듈 문서를 참조하세요. 다른 구현은 다르게 동작하며 CPython도 바뀔 수 있어요. 객체가 도달 불가능해질 때 즉시 최종화(finalization)된다고 의존하지 마세요(따라서 파일은 항상 명시적으로 닫아야 합니다).
구현의 추적·디버깅 기능을 사용하면 보통 수집될 수 있는 객체를 살아 있게 유지할 수 있다는 점에 주의하세요. 또한 try…except 문으로 예외를 잡는 것도 객체를 살아 있게 유지할 수 있습니다.
일부 객체는 열린 파일이나 창 같은 "외부" 리소스에 대한 참조를 포함합니다. 이 리소스들은 객체가 가비지 컬렉션될 때 해제되는 것으로 이해되지만, 가비지 컬렉션이 일어난다고 보장되지 않으므로 그러한 객체는 외부 리소스를 해제하는 명시적 방법, 보통 close() 메서드를 제공합니다. 프로그램은 그러한 객체를 명시적으로 닫는 것을 강력히 권장합니다. try…finally 문과 with 문이 이를 위한 편리한 방법을 제공해요.
일부 객체는 다른 객체에 대한 참조를 포함합니다. 이를 *컨테이너(containers)*라고 부릅니다. 컨테이너의 예는 튜플, 리스트, 딕셔너리입니다. 참조는 컨테이너 값의 일부입니다. 대부분의 경우 컨테이너의 값에 대해 말할 때는 포함된 객체의 정체성이 아니라 값을 의미합니다. 하지만 컨테이너의 변경 가능성에 대해 말할 때는 직접 포함된 객체의 정체성만 의미합니다. 따라서 불변 컨테이너(튜플 같은)가 변경 가능한 객체에 대한 참조를 포함하면, 그 변경 가능한 객체가 변경될 때 값이 바뀝니다.
타입은 객체 동작의 거의 모든 측면에 영향을 미칩니다. 객체 정체성의 중요성조차 어떤 의미에서 영향을 받습니다. 불변 타입의 경우 새 값을 계산하는 연산이 같은 타입과 값을 가진 기존 객체에 대한 참조를 실제로 반환할 수 있지만, 변경 가능한 객체에는 이것이 허용되지 않습니다. 예를 들어 a = 1; b = 1 후에 a와 b는 구현에 따라 값 1을 가진 같은 객체를 참조할 수도, 아닐 수도 있어요. int는 불변 타입이라 1에 대한 참조를 재사용할 수 있기 때문입니다. 이 동작은 사용된 구현에 의존하므로 의존해서는 안 되지만, 객체 정체성 테스트를 사용할 때 알아야 할 사항입니다. 그러나 c = []; d = [] 후에는 c와 d가 서로 다른 고유한 새 빈 리스트 두 개를 참조함이 보장됩니다. (e = f = []는 e와 f 모두에 같은 객체를 할당한다는 점에 주의하세요.)
3.2. 표준 타입 계층 (The standard type hierarchy)
아래는 Python에 내장된 타입의 목록입니다. 확장 모듈(구현에 따라 C, Java 또는 다른 언어로 작성)은 추가 타입을 정의할 수 있어요. 향후 Python 버전은 (예: 유리수, 효율적으로 저장된 정수 배열 등) 타입 계층에 타입을 추가할 수 있지만, 그러한 추가는 종종 표준 라이브러리를 통해 제공될 것입니다.
아래 타입 설명 중 일부에는 '특수 속성(special attributes)'을 나열하는 문단이 있습니다. 이는 구현에 대한 접근을 제공하며 일반적인 사용을 위한 것이 아닌 속성입니다. 그 정의는 향후 변경될 수 있습니다.
3.2.1. None
이 타입은 단일 값을 가집니다. 이 값을 가진 객체가 하나 있습니다. 이 객체는 내장 이름 None으로 접근됩니다. 많은 상황에서 값의 부재를 나타내는 데 사용되며, 예를 들어 명시적으로 아무것도 반환하지 않는 함수에서 반환됩니다. 참 값(truth value)은 거짓입니다.
3.2.2. NotImplemented
이 타입은 단일 값을 가집니다. 이 값을 가진 객체가 하나 있습니다. 이 객체는 내장 이름 NotImplemented로 접근됩니다. 숫자 메서드와 풍부 비교 메서드는 주어진 피연산자에 대해 해당 연산을 구현하지 않으면 이 값을 반환해야 합니다. (그러면 인터프리터는 연산자에 따라 반사 연산이나 다른 대체를 시도합니다.) 불리언 컨텍스트에서 평가되어서는 안 됩니다.
See
Implementing the arithmetic operations
자세한 내용.
Changed in version 3.9: 불리언 컨텍스트에서 NotImplemented를 평가하는 것이 더 이상 사용되지 않습니다( deprecat).
Changed in version 3.14: 불리언 컨텍스트에서 NotImplemented를 평가하면 이제 TypeError를 발생시킵니다. 이전에는 True로 평가되고 Python 3.9부터 DeprecationWarning을 발생시켰습니다.
3.2.3. Ellipsis
이 타입은 단일 값을 가집니다. 이 값을 가진 객체가 하나 있습니다. 이 객체는 리터럴 ... 또는 내장 이름 Ellipsis로 접근됩니다. 참 값은 참입니다.
3.2.4. numbers.Number
이들은 숫자 리터럴로 만들어지고 산술 연산자와 산술 내장 함수의 결과로 반환됩니다. 숫자 객체는 불변입니다. 일단 생성되면 값이 절대 변하지 않습니다. Python 숫자는 당연히 수학적 숫자와 강하게 관련이 있지만, 컴퓨터에서의 수치 표현의 한계에 영향을 받습니다.
__repr__()와 __str__()로 계산된 숫자 클래스의 문자열 표현은 다음 속성들을 가집니다:
해당 클래스 생성자에 전달되면 원래 숫자와 같은 값을 가진 객체를 만드는 유효한 숫자 리터럴입니다.
가능하면 표현은 10진수입니다.
소수점 앞의 단일 0을 제외하고 선행 0은 표시되지 않습니다.
소수점 뒤의 단일 0을 제외하고 후행 0은 표시되지 않습니다.
부호는 숫자가 음수일 때만 표시됩니다.
Python은 정수, 부동소수점 수, 복소수를 구분합니다:
3.2.4.1. numbers.Integral
이는 수학적 정수 집합(양수와 음수)의 요소를 나타냅니다.
Note
정수 표현 규칙은 음의 정수를 포함하는 시프트·마스크 연산에 가장 의미 있는 해석을 주기 위한 것입니다.
두 가지 정수 타입이 있습니다:
정수 (int)
이들은 사용 가능한 (가상) 메모리만의 제한으로 무한 범위의 숫자를 나타냅니다. 시프트·마스크 연산을 위해 이진 표현이 가정되며, 음수는 왼쪽으로 확장되는 무한 부호 비트 문자열의 착각을 주는 2의 보수 변형으로 표현됩니다.
불리언 (bool)
이들은 참 값 True와 False를 나타냅니다. 값 False와 True를 나타내는 두 객체가 유일한 불리언 객체입니다. 불리언 타입은 정수 타입의 하위 타입이며, 불리언 값은 거의 모든 컨텍스트에서 각각 0과 1처럼 동작합니다. 단, 문자열로 변환될 때는 각각 "False" 또는 "True" 문자열이 반환된다는 예외가 있습니다.
3.2.4.2. numbers.Real (float)
이들은 머신 수준의 배정밀도 부동소수점 수를 나타냅니다. 허용되는 범위와 오버플로 처리에 대해서는 기반 머신 아키텍처(및 C 또는 Java 구현)의 영향을 받습니다. Python은 단정밀도 부동소수점 수를 지원하지 않습니다. 보통 단정밀도를 사용하는 이유인 프로세서·메모리 사용의 절약이 Python에서 객체를 사용하는 오버헤드에 비해 무시할 만하므로, 두 종류의 부동소수점 수로 언어를 복잡하게 할 이유가 없습니다.
3.2.4.3. numbers.Complex (complex)
이들은 복소수를 한 쌍의 머신 수준 배정밀도 부동소수점 수로 나타냅니다. 부동소수점 수와 같은 주의사항이 적용됩니다. 복소수 z의 실수부와 허수부는 읽기 전용 속성 z.real과 z.imag로 가져올 수 있습니다.
3.2.5. 시퀀스 (Sequences)
이들은 음이 아닌 숫자로 인덱싱되는 유한한 순서 집합을 나타냅니다. 내장 함수 len()은 시퀀스의 항목 수를 반환합니다. 시퀀스 길이가 n이면 인덱스 집합은 숫자 0, 1, …, n-1을 포함합니다. 시퀀스 a의 항목 i는 a[i]로 선택됩니다. 내장 시퀀스를 포함한 일부 시퀀스는 시퀀스 길이를 더해서 음수 첨자를 해석합니다. 예를 들어 a[-2]는 a[n-2]와 같으며, 길이 n의 시퀀스 a의 끝에서 두 번째 항목입니다.
결과 값은 시퀀스의 항목 수보다 작은 음이 아닌 정수여야 합니다. 그렇지 않으면 IndexError가 발생합니다.
시퀀스는 슬라이싱도 지원합니다. a[start:stop]는 인덱스 k가 start <= k < stop인 모든 항목을 선택합니다. 표현식으로 사용될 때 슬라이스는 같은 타입의 시퀀스입니다. 음수 첨자에 대한 위의 설명은 음수 슬라이스 위치에도 적용됩니다. 슬라이스 위치가 0보다 작거나 시퀀스 길이보다 크다고 해서 오류가 발생하지 않는다는 점에 주의하세요.
start가 없거나 None이면 슬라이싱은 start가 0인 것처럼 동작합니다. stop이 없거나 None이면 슬라이싱은 stop이 시퀀스 길이와 같은 것처럼 동작합니다.
일부 시퀀스는 세 번째 "step" 매개변수가 있는 "확장 슬라이싱"도 지원합니다. a[i:j:k]는 인덱스 x가 x = i + n*k, n >= 0, i <= x < j인 a의 모든 항목을 선택합니다.
시퀀스는 변경 가능성에 따라 구분됩니다:
3.2.5.1. 불변 시퀀스 (Immutable sequences)
불변 시퀀스 타입의 객체는 생성된 후 변경할 수 없습니다. (객체가 다른 객체에 대한 참조를 포함하면 그 다른 객체는 변경 가능하고 변경될 수 있습니다. 하지만 불변 객체가 직접 참조하는 객체의 집합은 변경할 수 없습니다.)
다음 타입들은 불변 시퀀스입니다:
문자열 (Strings)
문자열(str)은 문자(characters), 더 형식적으로는 *유니코드 코드 포인트(Unicode code points)*를 나타내는 값들의 시퀀스입니다. 0부터 0x10FFFF 범위의 모든 코드 포인트는 문자열로 나타낼 수 있습니다.
Python에는 전용 문자 타입이 없습니다. 대신 문자열의 모든 코드 포인트는 길이 1의 문자열 객체로 표현됩니다.
내장 함수 ord()는 코드 포인트를 문자열 형태에서 0부터 0x10FFFF 범위의 정수로 변환합니다. chr()는 0부터 0x10FFFF 범위의 정수를 길이 1의 해당 문자열 객체로 변환합니다. str.encode()는 주어진 텍스트 인코딩을 사용해 str을 bytes로 변환하는 데 사용될 수 있고, bytes.decode()는 반대 작업에 사용될 수 있습니다.
튜플 (Tuples)
tuple의 항목은 임의의 Python 객체입니다. 두 개 이상의 항목으로 이루어진 튜플은 쉼표로 구분된 표현식 목록으로 형성됩니다. 한 항목의 튜플('싱글턴')은 표현식에 쉼표를 붙여 형성할 수 있습니다(표현식 자체는 튜플을 만들지 않습니다. 괄호는 표현식 그룹화에 사용 가능해야 하므로). 빈 튜플은 빈 괄호 쌍으로 형성할 수 있습니다.
바이트 (Bytes)
bytes 객체는 불변 배열입니다. 항목은 0 <= x < 256 범위의 정수로 표현되는 8비트 바이트입니다. 바이트 리터럴(b'abc' 같은)과 내장 bytes() 생성자를 사용해 bytes 객체를 만들 수 있습니다. 또한 bytes 객체는 decode() 메서드를 통해 문자열로 디코딩될 수 있습니다.
3.2.5.2. 변경 가능 시퀀스 (Mutable sequences)
변경 가능 시퀀스는 생성된 후 변경될 수 있습니다. 첨자·슬라이싱 표기법이 할당과 del(삭제) 문의 대상으로 사용될 수 있습니다.
Note
collections와 array 모듈은 변경 가능한 시퀀스 타입의 추가 예를 제공합니다.
현재 두 가지 내재 변경 가능 시퀀스 타입이 있습니다:
리스트 (Lists)
리스트의 항목은 임의의 Python 객체입니다. 리스트는 쉼표로 구분된 표현식 목록을 대괄호 안에 두어 형성됩니다. (길이 0이나 1의 리스트를 형성하는 특별한 경우는 필요 없다는 점에 주의하세요.)
바이트 배열 (Byte Arrays)
bytearray 객체는 변경 가능한 배열입니다. 내장 bytearray() 생성자로 만들어집니다. 변경 가능하다는 점(따라서 해시 불가능)을 제외하면, 바이트 배열은 불변 bytes 객체와 동일한 인터페이스와 기능을 제공합니다.
3.2.6. 집합 타입 (Set types)
이들은 고유하고 불변인 객체들의 순서 없는 유한 집합을 나타냅니다. 따라서 어떤 첨자로도 인덱싱할 수 없습니다. 하지만 반복될 수 있고, 내장 함수 len()이 집합의 항목 수를 반환합니다. 집합의 흔한 용도는 빠른 멤버십 테스트, 시퀀스에서 중복 제거, 교집합·합집합·차집합·대칭 차집합 같은 수학적 연산 계산입니다.
집합 요소에 대해 딕셔너리 키와 같은 불변성 규칙이 적용됩니다. 숫자 타입은 숫자 비교의 일반 규칙을 따른다는 점에 주의하세요. 두 숫자가 같게 비교되면(예: 1과 1.0) 그중 하나만 집합에 포함될 수 있습니다.
현재 두 가지 내재 집합 타입이 있습니다:
집합 (Sets)
변경 가능한 집합을 나타냅니다. 내장 set() 생성자로 만들어지고, add() 같은 여러 메서드로 나중에 수정될 수 있습니다.
프로즌셋 (Frozen sets)
불변 집합을 나타냅니다. 내장 frozenset() 생성자로 만들어집니다. frozenset은 불변이고 해시 가능하므로, 다른 집합의 요소나 딕셔너리 키로 다시 사용될 수 있습니다.
3.2.7. 매핑 (Mappings)
이들은 임의의 인덱스 집합으로 인덱싱되는 유한한 객체 집합을 나타냅니다. 첨자 표기 a[k]는 매핑 a에서 k로 인덱싱된 항목을 선택합니다. 이는 표현식과 할당·del 문의 대상으로 사용될 수 있습니다. 내장 함수 len()은 매핑의 항목 수를 반환합니다.
현재 단일 내재 매핑 타입이 있습니다:
3.2.7.1. 딕셔너리 (Dictionaries)
이들은 거의 임의의 값으로 인덱싱되는 유한한 객체 집합을 나타냅니다. 키로 허용되지 않는 유일한 값 타입은 리스트나 딕셔너리, 또는 객체 정체성이 아니라 값으로 비교되는 다른 변경 가능 타입을 포함하는 값입니다. 그 이유는 딕셔너리의 효율적인 구현이 키의 해시 값이 일정하게 유지되기를 요구하기 때문입니다. 키에 사용되는 숫자 타입은 숫자 비교의 일반 규칙을 따릅니다. 두 숫자가 같게 비교되면(예: 1과 1.0) 같은 딕셔너리 항목을 인덱싱하는 데 교환적으로 사용될 수 있습니다.
딕셔너리는 삽입 순서를 보존합니다. 즉 키는 딕셔너리에 순차적으로 추가된 순서대로 생성됩니다. 기존 키를 교체해도 순서는 바뀌지 않지만, 키를 제거하고 다시 삽입하면 이전 위치가 아니라 끝에 추가됩니다.
딕셔너리는 변경 가능하며 {} 표기( Dictionary displays 섹션 참조)로 만들 수 있습니다.
확장 모듈 dbm.ndbm과 dbm.gnu, 그리고 collections 모듈은 매핑 타입의 추가 예를 제공합니다.
Changed in version 3.7: Python 3.6 이전 버전에서는 딕셔너리가 삽입 순서를 보존하지 않았습니다. CPython 3.6에서는 삽입 순서가 보존되었지만, 그 당시에는 언어 보장이라기보다 구현 세부사항으로 간주되었습니다.
3.2.8. 호출 가능 타입 (Callable types)
함수 호출 연산(Calls 섹션 참조)을 적용할 수 있는 타입들입니다:
3.2.8.1. 사용자 정의 함수 (User-defined functions)
사용자 정의 함수 객체는 함수 정의(Function definitions 섹션 참조)로 만들어집니다. 함수의 형식 매개변수 목록과 같은 수의 항목을 포함하는 인수 목록으로 호출되어야 합니다.
3.2.8.1.1. 특수 읽기 전용 속성 (Special read-only attributes)
| Attribute | Meaning |
|---|---|
| function.builtins | 함수의 내장(builtins) 네임스페이스를 담는 dictionary에 대한 참조. Added in version 3.10. |
| function.globals | 함수의 전역 변수를 담는 dictionary에 대한 참조 — 함수가 정의된 모듈의 전역 네임스페이스. |
| function.closure | 함수의 code object의 co_freevars 속성에 지정된 이름에 대한 바인딩을 포함하는 셀(cell)들의 None 또는 tuple. 셀 객체는 cell_contents 속성을 가집니다. 이를 사용해 셀의 값을 가져오고 설정할 수 있습니다. |
3.2.8.1.2. 특수 쓰기 가능 속성 (Special writable attributes)
이 속성들 대부분은 할당된 값의 타입을 검사합니다:
| Attribute | Meaning |
|---|---|
| function.doc | 함수의 문서 문자열, 사용 불가하면 None. |
| function.name | 함수의 이름. __name__ attributes도 참조. |
| function.qualname | 함수의 정규화된 이름. __qualname__ attributes도 참조. Added in version 3.3. |
| function.module | 함수가 정의된 모듈의 이름, 사용 불가하면 None. |
| function.defaults | 기본값을 가진 매개변수들의 기본 매개변수 값을 포함하는 tuple, 기본값을 가진 매개변수가 없으면 None. |
| function.code | 컴파일된 함수 본문을 나타내는 코드 객체. |
| function.dict | 임의 함수 속성을 지원하는 네임스페이스. __dict__ attributes도 참조. |
| function.annotations | 매개변수 주석을 포함하는 dictionary. 딕셔너리 키는 매개변수 이름이고, 반환 주석이 있으면 'return'. object.__annotations__도 참조. Changed in version 3.14: 주석이 이제 지연 평가됩니다. PEP 649 참조. |
| function.annotate | 이 함수에 대한 annotate 함수, 주석이 없으면 None. object.__annotate__ 참조. Added in version 3.14. |
| function.kwdefaults | 키워드 전용 매개변수에 대한 기본값을 포함하는 dictionary. |
| function.type_params | 제네릭 함수의 타입 매개변수를 포함하는 tuple. Added in version 3.12. |
함수 객체는 임의 속성의 설정·획득도 지원하며, 예를 들어 함수에 메타데이터를 첨부하는 데 사용할 수 있습니다. 일반 속성 점 표기법이 그러한 속성을 얻고 설정하는 데 사용됩니다.
CPython implementation detail: CPython의 현재 구현은 사용자 정의 함수에서만 함수 속성을 지원합니다. 내장 함수의 함수 속성은 향후 지원될 수 있습니다.
함수 정의에 대한 추가 정보는 코드 객체(__code__ 속성으로 접근 가능)에서 가져올 수 있습니다.
3.2.8.2. 인스턴스 메서드 (Instance methods)
인스턴스 메서드 객체는 클래스, 클래스 인스턴스, 그리고 임의의 호출 가능 객체(보통 사용자 정의 함수)를 결합합니다.
특수 읽기 전용 속성:
| Attribute | Meaning |
|---|---|
| method.self | 메서드가 바인딩된 클래스 인스턴스 객체를 가리킵니다. |
| method.func | 원래 함수 객체를 가리킵니다. |
| method.doc | 메서드의 문서(method.__func__.__doc__와 같음). 원래 함수에 docstring이 있으면 string, 없으면 None. |
| method.name | 메서드의 이름(method.__func__.__name__과 같음). |
| method.module | 메서드가 정의된 모듈의 이름, 사용 불가하면 None. |
메서드는 기반 함수 객체의 임의 함수 속성에 접근(설정은 아님)도 지원합니다.
사용자 정의 메서드 객체는 클래스의 속성을(어쩌면 그 클래스의 인스턴스를 통해) 얻을 때, 그 속성이 사용자 정의 함수 객체나 classmethod 객체라면 생성될 수 있습니다.
인스턴스 메서드 객체가 그 인스턴스 중 하나를 통해 클래스에서 사용자 정의 함수 객체를 가져옴으로써 만들어지면, 그 __self__ 속성은 인스턴스이고 메서드 객체는 *바인딩(bound)*되었다고 합니다. 새 메서드의 __func__ 속성은 원래 함수 객체입니다.
인스턴스 메서드 객체가 클래스 또는 인스턴스에서 classmethod 객체를 가져옴으로써 만들어지면, 그 __self__ 속성은 클래스 자체이고 __func__ 속성은 클래스 메서드의 기반이 되는 함수 객체입니다.
인스턴스 메서드 객체가 호출되면 기반 함수(__func__)가 호출되며, 클래스 인스턴스(__self__)가 인수 목록 앞에 삽입됩니다. 예를 들어 C가 함수 f()의 정의를 포함하는 클래스이고 x가 C의 인스턴스일 때, x.f(1) 호출은 C.f(x, 1) 호출과 동등합니다.
인스턴스 메서드 객체가 classmethod 객체에서 파생되면 __self__에 저장된 "클래스 인스턴스"는 실제로 클래스 자체이므로, x.f(1) 또는 C.f(1)로 호출하는 것 모두 f(C,1)(여기서 f는 기반 함수)를 호출하는 것과 동등합니다.
클래스 인스턴스의 속성인 사용자 정의 함수는 바인딩 메서드로 변환되지 않는다는 점을 기억하는 것이 중요합니다. 이 변환은 함수가 클래스의 속성일 때 만 일어납니다.
3.2.8.3. 제너레이터 함수 (Generator functions)
yield 표현식(Yield expressions 섹션 참조)을 포함하는 함수 또는 메서드를 제너레이터 함수라고 합니다. 그러한 함수는 호출되면 항상 함수 본문을 실행하는 데 사용할 수 있는 반복자 객체를 반환합니다. 반복자의 iterator.__next__() 메서드를 호출하면 함수가 yield 표현식으로 값을 제공할 때까지 실행됩니다. 함수가 return 문을 실행하거나 끝에 도달하면 StopIteration 예외가 발생하고 반복자는 반환할 값 집합의 끝에 도달합니다.
3.2.8.4. 코루틴 함수 (Coroutine functions)
async def로 정의된 함수 또는 메서드를 코루틴 함수라고 합니다. 그러한 함수는 호출되면 코루틴 객체를 반환합니다. await 표현식과 async with, async for 문을 포함할 수 있습니다. Coroutine Objects 섹션도 참조하세요.
3.2.8.5. 비동기 제너레이터 함수 (Asynchronous generator functions)
async def로 정의되고 yield 표현식을 포함하는 함수 또는 메서드를 비동기 제너레이터 함수라고 합니다. 그러한 함수는 호출되면 함수 본문을 실행하기 위해 async for 문에서 사용할 수 있는 비동기 반복자 객체를 반환합니다.
비동기 반복자의 aiterator.__anext__ 메서드를 호출하면 어웨이터블이 반환되고, 이를 await하면 yield 표현식으로 값을 제공할 때까지 실행됩니다. 함수가 빈 return 문을 실행하거나 끝에 도달하면 StopAsyncIteration 예외가 발생하고 비동기 반복자는 yield할 값 집합의 끝에 도달합니다.
3.2.8.6. 내장 함수 (Built-in functions)
내장 함수 객체는 C 함수 주변의 래퍼입니다. 내장 함수의 예는 len()과 math.sin()(math는 표준 내장 모듈)입니다. 인수의 수와 타입은 C 함수가 결정합니다. 특수 읽기 전용 속성:
__doc__는 함수의 문서 문자열, 사용 불가하면 None. function.__doc__ 참조.
__name__은 함수의 이름. function.__name__ 참조.
__self__는 None으로 설정됩니다(하지만 다음 항목 참조).
__module__은 함수가 정의된 모듈의 이름 또는 사용 불가하면 None. function.__module__ 참조.
3.2.8.7. 내장 메서드 (Built-in methods)
이것은 실제로 내장 함수의 다른 변장으로, 이번에는 C 함수에 암시적 추가 인수로 전달되는 객체를 포함합니다. 내장 메서드의 예는 alist가 리스트 객체일 때 alist.append()입니다. 이 경우 특수 읽기 전용 속성 __self__는 alist가 나타내는 객체로 설정됩니다. (이 속성은 other instance methods와 동일한 의미를 가집니다.)
3.2.8.8. 클래스 (Classes)
클래스는 호출 가능합니다. 이 객체들은 보통 자기 자신의 새 인스턴스에 대한 팩토리로 동작하지만, __new__()를 오버라이드하는 클래스 타입에는 변형이 가능합니다. 호출의 인수는 __new__()에 전달되고, 일반적인 경우 새 인스턴스를 초기화하기 위해 __init__()에도 전달됩니다.
3.2.8.9. 클래스 인스턴스 (Class Instances)
임의 클래스의 인스턴스는 그 클래스에서 __call__() 메서드를 정의하여 호출 가능하게 만들 수 있습니다.
3.2.9. 모듈 (Modules)
모듈은 Python 코드의 기본 조직 단위이며, import 문에 의해 호출되거나 importlib.import_module()과 내장 __import__() 같은 함수를 호출함으로써 호출되는 import 시스템에 의해 만들어집니다. 모듈 객체는 dictionary 객체로 구현된 네임스페이스를 가집니다(이것은 모듈에 정의된 함수의 __globals__ 속성이 참조하는 딕셔너리입니다). 속성 참조는 이 딕셔너리에서의 조회로 변환됩니다. 예를 들어 m.x는 m.__dict__["x"]와 동등합니다. 모듈 객체는 모듈을 초기화하는 데 사용되는 코드 객체를 포함하지 않습니다(초기화가 완료되면 필요 없어지므로).
속성 할당은 모듈의 네임스페이스 딕셔너리를 갱신합니다. 예를 들어 m.x = 1은 m.__dict__["x"] = 1과 동등합니다.
3.2.9.1. 모듈 객체의 import 관련 속성 (Import-related attributes on module objects)
모듈 객체는 import 시스템과 관련된 다음 속성들을 가집니다. 모듈이 import 시스템과 관련된 메커니즘으로 만들어질 때, 로더가 모듈을 실행하고 로드하기 전에 이 속성들은 모듈의 spec에 기반해 채워집니다.
import 시스템을 사용하지 않고 동적으로 모듈을 만들려면, 다양한 import 제어 속성을 적절한 값으로 설정하는 importlib.util.module_from_spec()를 사용하는 것이 좋습니다. types.ModuleType 생성자를 사용해 모듈을 직접 만들 수도 있지만, 이 접근은 생성 후 대부분의 속성을 모듈 객체에 수동으로 설정해야 하므로 오류가 더 발생하기 쉽습니다.
Caution
__name__을 제외하고, 이 하위 섹션에 나열된 다른 개별 속성 대신 __spec__과 그 속성에 의존하는 것을 강력히 권장합니다. __spec__에서 속성을 갱신해도 모듈 자체의 해당 속성은 갱신되지 않는다는 점에 주의하세요:
>>> import typing
>>> typing.__name__, typing.__spec__.name
('typing', 'typing')
>>> typing.__spec__.name = 'spelling'
>>> typing.__name__, typing.__spec__.name
('typing', 'spelling')
>>> typing.__name__ = 'keyboard_smashing'
>>> typing.__name__, typing.__spec__.name
('keyboard_smashing', 'spelling')
module.name
import 시스템에서 모듈을 고유하게 식별하는 데 사용되는 이름. 직접 실행된 모듈의 경우 "__main__"으로 설정됩니다.
이 속성은 모듈의 정규화된 이름으로 설정되어야 합니다. module.__spec__.name의 값과 일치할 것으로 기대됩니다.
module.spec
모듈의 import 시스템 관련 상태의 기록.
모듈을 import할 때 사용된 module spec으로 설정됩니다. 자세한 내용은 Module specs 참조. Added in version 3.4.
module.package
모듈이 속한 패키지.
모듈이 최상위(즉 어떤 특정 패키지의 일부가 아님)이면 속성은 ''(빈 문자열)로 설정되어야 합니다. 그렇지 않으면 모듈의 패키지 이름(모듈 자체가 패키지라면 module.__name__과 같을 수 있음)으로 설정되어야 합니다. 자세한 내용은 PEP 366 참조.
이 속성은 메인 모듈에 대한 명시적 상대 import를 계산할 때 __name__ 대신 사용됩니다. types.ModuleType 생성자로 동적으로 만들어진 모듈의 경우 None으로 기본 설정됩니다. 속성이 str로 설정되도록 하려면 대신 importlib.util.module_from_spec()를 사용하세요.
module.__spec__.parent를 module.__package__ 대신 사용하는 것을 강력히 권장합니다. __package__는 이제 __spec__.parent가 설정되지 않았을 때의 대체(fallback)로만 사용되며, 이 대체 경로는 더 이상 사용되지 않습니다.
Changed in version 3.4: 이 속성은 이제 types.ModuleType 생성자로 동적으로 만들어진 모듈에 대해 None으로 기본 설정됩니다. 이전에는 선택 사항이었습니다.
Changed in version 3.6: __package__의 값은 __spec__.parent와 같을 것으로 기대됩니다. __package__는 이제 import 해석 중 __spec__.parent가 정의되지 않았을 때만 대체로 사용됩니다.
Changed in version 3.10: import 해석이 __spec__.parent 대신 __package__로 대체되면 ImportWarning이 발생합니다.
Changed in version 3.12: import 해석 중 __package__로 대체될 때 ImportWarning 대신 DeprecationWarning을 발생시킵니다.
Deprecated since version 3.13, will be removed in version 3.15: __package__는 import 시스템이나 표준 라이브러리에 의해 더 이상 설정되거나 고려되지 않을 것입니다.
module.loader
import 메커니즘이 모듈을 로드하는 데 사용한 로더 객체.
이 속성은 대부분 내부 검사에 유용하지만, 로더 특정 기능(예: 로더와 연관된 데이터 얻기)에 사용될 수 있습니다.
__loader__는 types.ModuleType 생성자로 동적으로 만들어진 모듈의 경우 None으로 기본 설정됩니다. 로더 객체로 설정되도록 하려면 importlib.util.module_from_spec()를 대신 사용하세요.
module.__spec__.loader를 module.__loader__ 대신 사용하는 것을 강력히 권장합니다.
Changed in version 3.4: 이 속성은 이제 types.ModuleType 생성자로 동적으로 만들어진 모듈에 대해 None으로 기본 설정됩니다. 이전에는 선택 사항이었습니다.
Deprecated since version 3.12, will be removed in version 3.16: __spec__.loader를 설정하지 않고 모듈에 __loader__를 설정하는 것은 더 이상 사용되지 않습니다. Python 3.16에서는 __loader__가 import 시스템이나 표준 라이브러리에 의해 더 이상 설정되거나 고려되지 않을 것입니다.
module.path
패키지의 하위 모듈이 발견될 위치를 나열하는 (어쩌면 빈) 문자열 시퀀스. 비-패키지 모듈은 __path__ 속성을 가지지 않아야 합니다. 자세한 내용은 path attributes on modules 참조.
module.__spec__.submodule_search_locations를 module.__path__ 대신 사용하는 것을 강력히 권장합니다.
module.file
module.cached
__file__과 __cached__는 모두 설정될 수도 있고 아닐 수도 있는 선택적 속성입니다. 둘 다 사용 가능할 때 str이어야 합니다.
__file__은 모듈이 로드된 파일의 경로 이름(파일에서 로드된 경우) 또는 공유 라이브러리에서 동적으로 로드된 확장 모듈의 공유 라이브러리 파일 경로 이름을 나타냅니다. 인터프리터에 정적으로 링크된 C 모듈 같은 특정 유형의 모듈에서는 없을 수 있고, 의미가 없으면 import 시스템이 설정하지 않기로 선택할 수 있습니다(예: 데이터베이스에서 로드된 모듈).
__file__이 설정되면 __cached__ 속성도 설정될 수 있는데, 이는 코드의 컴파일된 버전(예: 바이트 컴파일된 파일)의 경로입니다. 이 속성을 설정하기 위해 파일이 존재할 필요는 없습니다. 경로는 단순히 컴파일된 파일이 존재할 위치를 가리킬 수 있습니다(PEP 3147 참조).
__file__이 설정되지 않아도 __cached__가 설정될 수 있다는 점에 주의하세요. 하지만 그 시나리오는 매우 비정형적입니다. 궁극적으로 로더가 파인더(finder)가 제공한 모듈 spec(__file__과 __cached__가 파생되는)을 사용합니다. 따라서 로더가 캐시된 모듈에서는 로드할 수 있지만 파일에서는 로드하지 않는 경우, 그 비정형적 시나리오가 적절할 수 있습니다.
module.__spec__.cached를 module.__cached__ 대신 사용하는 것을 강력히 권장합니다.
Deprecated since version 3.13, will be removed in version 3.15: __spec__.cached를 설정하지 않고 모듈에 __cached__를 설정하는 것은 더 이상 사용되지 않습니다. Python 3.15에서는 __cached__가 import 시스템이나 표준 라이브러리에 의해 더 이상 설정되거나 고려되지 않을 것입니다.
3.2.9.2. 모듈 객체의 다른 쓰기 가능 속성 (Other writable attributes on module objects)
위에 나열된 import 관련 속성 외에도 모듈 객체는 다음 쓰기 가능 속성들을 가집니다:
module.doc
모듈의 문서 문자열, 사용 불가하면 None. __doc__ attributes도 참조.
module.annotations
모듈 본문 실행 중 수집된 변수 주석을 포함하는 딕셔너리. __annotations__ 작업 모범 사례는 annotationlib 참조.
Changed in version 3.14: 주석이 이제 지연 평가됩니다. PEP 649 참조.
module.annotate
이 모듈에 대한 annotate 함수, 모듈에 주석이 없으면 None. __annotate__ attributes도 참조. Added in version 3.14.
3.2.9.3. 모듈 딕셔너리 (Module dictionaries)
모듈 객체는 다음 특수 읽기 전용 속성도 가집니다:
module.dict
모듈의 네임스페이스(딕셔너리 객체). 여기 나열된 속성 중 유일하게 __dict__는 모듈 내부에서 전역 변수로 접근할 수 없습니다. 모듈 객체의 속성으로만 접근할 수 있습니다.
CPython implementation detail: CPython이 모듈 딕셔너리를 지우는 방식 때문에, 딕셔너리에 여전히 활성 참조가 있어도 모듈이 스코프에서 벗어나면 모듈 딕셔너리가 지워집니다. 이를 피하려면 딕셔너리를 복사하거나, 딕셔너리를 직접 사용하는 동안 모듈을 유지하세요.
3.2.10. 사용자 정의 클래스 (Custom classes)
사용자 정의 클래스 타입은 보통 클래스 정의(Class definitions 섹션 참조)로 만들어집니다. 클래스는 딕셔너리 객체로 구현된 네임스페이스를 가집니다. 클래스 속성 참조는 이 딕셔너리에서의 조회로 변환됩니다. 예를 들어 C.x는 C.__dict__["x"]로 변환됩니다(속성을 찾는 다른 방법을 허용하는 여러 훅이 있지만). 속성 이름이 거기서 발견되지 않으면 기반 클래스에서 속성 검색이 계속됩니다. 이 기반 클래스 검색은 C3 메서드 해석 순서를 사용하며, 공통 조상으로 이어지는 여러 상속 경로가 있는 '다이아몬드' 상속 구조가 있어도 올바르게 동작합니다. Python이 사용하는 C3 MRO에 대한 추가 세부사항은 The Python 2.3 Method Resolution Order에서 찾을 수 있습니다.
클래스 속성 참조가(클래스 C에 대해) 클래스 메서드 객체를 산출하면 __self__ 속성이 C인 인스턴스 메서드 객체로 변환됩니다. staticmethod 객체를 산출하면 정적 메서드 객체가 감싼 객체로 변환됩니다. 클래스에서 가져온 속성이 __dict__에 실제로 포함된 속성과 다를 수 있는 또 다른 방법은 Implementing Descriptors 섹션을 참조하세요.
클래스 속성 할당은 클래스의 딕셔너리를 갱신하며, 기반 클래스의 딕셔너리는 결코 갱신하지 않습니다.
클래스 객체는 호출될 수 있고(위 참조) 클래스 인스턴스(아래 참조)를 산출합니다.
3.2.10.1. 특수 속성 (Special attributes)
| Attribute | Meaning |
|---|---|
| type.name | 클래스의 이름. __name__ attributes도 참조. |
| type.qualname | 클래스의 정규화된 이름. __qualname__ attributes도 참조. |
| type.module | 클래스가 정의된 모듈의 이름. |
| type.dict | 클래스의 네임스페이스의 읽기 전용 보기를 제공하는 mapping proxy. __dict__ attributes도 참조. |
| type.bases | 클래스의 기반들을 포함하는 tuple. 대부분의 경우 class X(A, B, C)로 정의된 클래스에 대해 X.__bases__는 정확히 (A, B, C)와 같습니다. |
| type.base | CPython implementation detail: 인스턴스의 메모리 레이아웃을 담당하는 상속 체인의 단일 기반 클래스. 이 속성은 C 수준의 tp_base에 대응합니다. |
| type.doc | 클래스의 문서 문자열, 정의되지 않았으면 None. 하위 클래스에 상속되지 않습니다. |
| type.annotations | 클래스 본문 실행 중 수집된 변수 주석을 포함하는 딕셔너리. __annotations__ attributes도 참조. __annotations__ 작업 모범 사례는 annotationlib을 참조하세요. 이 속성에 직접 접근하는 대신 annotationlib.get_annotations()를 사용하세요. Warning: 클래스 객체에서 __annotations__ 속성에 직접 접근하면 잘못된 클래스의 주석을 반환할 수 있습니다. 특히 클래스, 기반 클래스 또는 메타클래스가 from __future__ import annotations 하에 정의된 특정 경우에 그렇습니다. 자세한 내용은 749 참조. 이 속성은 특정 내장 클래스에는 존재하지 않습니다. __annotations__가 없는 사용자 정의 클래스에서는 빈 딕셔너리입니다. Changed in version 3.14: 주석이 이제 지연 평가됩니다. PEP 649 참조. |
| type.annotate() | 이 클래스에 대한 annotate 함수, 주석이 없으면 None. __annotate__ attributes도 참조. Added in version 3.14. |
| type.type_params | 제네릭 클래스의 타입 매개변수를 포함하는 tuple. Added in version 3.12. |
| type.static_attributes | 본문의 어떤 함수에서든 self.X로 할당되는 이 클래스의 속성 이름들을 포함하는 tuple. Added in version 3.13. |
| type.firstlineno | 데코레이터를 포함한 클래스 정의 첫 줄의 줄 번호. __module__ 속성을 설정하면 타입의 딕셔너리에서 __firstlineno__ 항목이 제거됩니다. Added in version 3.13. |
| type.mro | 메서드 해석 중 기반 클래스를 찾을 때 고려되는 클래스들의 tuple. |
3.2.10.2. 특수 메서드 (Special methods)
위에서 설명한 특수 속성 외에 모든 Python 클래스는 다음 두 메서드도 사용할 수 있습니다:
type.mro()
이 메서드는 메타클래스가 오버라이드하여 그 인스턴스들의 메서드 해석 순서를 사용자화할 수 있습니다. 클래스 인스턴스화 시 호출되며, 그 결과는 __mro__에 저장됩니다.
type.subclasses()
각 클래스는 즉시 하위 클래스들에 대한 약한 참조 목록을 유지합니다. 이 메서드는 아직 살아 있는 모든 참조의 목록을 반환합니다. 목록은 정의 순서입니다. 예:
>>> class A: pass
>>> class B(A): pass
>>> A.__subclasses__()
[<class 'B'>]
3.2.11. 클래스 인스턴스 (Class instances)
클래스 인스턴스는 클래스 객체를 호출하여 만들어집니다(위 참조). 클래스 인스턴스는 딕셔너리로 구현된 네임스페이스를 가지며, 속성 참조가 처음으로 검색되는 곳입니다. 속성이 거기서 발견되지 않고 인스턴스의 클래스에 그 이름의 속성이 있으면 검색은 클래스 속성으로 계속됩니다. 클래스 속성이 사용자 정의 함수 객체인 것이 발견되면 __self__ 속성이 인스턴스인 인스턴스 메서드 객체로 변환됩니다. 정적 메서드와 클래스 메서드 객체도 변환됩니다. 위 "Classes" 참조. 인스턴스를 통해 가져온 클래스 속성이 클래스의 __dict__에 실제로 저장된 객체와 다른 또 다른 방법은 Implementing Descriptors 섹션을 참조하세요. 클래스 속성이 발견되지 않고 객체의 클래스에 __getattr__() 메서드가 있으면 그것이 호출되어 조회를 수행합니다.
속성 할당과 삭제는 인스턴스의 딕셔너리를 갱신하며, 클래스의 딕셔너리는 결코 갱신하지 않습니다. 클래스에 __setattr__() 또는 __delattr__() 메서드가 있으면 인스턴스 딕셔너리를 직접 갱신하는 대신 그것이 호출됩니다.
클래스 인스턴스는 특정 특수 이름의 메서드를 가지면 숫자, 시퀀스 또는 매핑인 척할 수 있습니다. Special method names 섹션 참조.
3.2.11.1. 특수 속성 (Special attributes)
object.class
클래스 인스턴스가 속한 클래스.
object.dict
객체의 (쓰기 가능한) 속성을 저장하는 데 사용되는 딕셔너리 또는 다른 매핑 객체. 모든 인스턴스가 __dict__ 속성을 가지는 것은 아닙니다. 자세한 내용은 slots 섹션 참조.
3.2.12. I/O 객체 (I/O objects, 파일 객체라고도 함)
파일 객체는 열린 파일을 나타냅니다. 파일 객체를 만드는 다양한 단축키가 있습니다. open() 내장 함수, 그리고 os.popen(), os.fdopen(), 소켓 객체의 makefile() 메서드(그리고 어쩌면 확장 모듈이 제공하는 다른 함수·메서드)가 있습니다.
파일 객체는 일반 코드에서 사용을 단순화하기 위해 아래 나열된 공통 메서드를 구현합니다. 이들은 With Statement Context Managers가 될 것으로 기대됩니다.
sys.stdin, sys.stdout, sys.stderr 객체는 인터프리터의 표준 입력·출력·오류 스트림에 대응하는 파일 객체로 초기화됩니다. 모두 텍스트 모드로 열리므로 io.TextIOBase 추상 클래스가 정의하는 인터페이스를 따릅니다.
file.read(size=-1, /)
파일에서 최대 size 데이터를 가져옵니다. 편의상 size가 지정되지 않거나 -1이면 사용 가능한 모든 데이터를 가져옵니다.
file.write(data, /)
data를 파일에 저장합니다.
file.close()
모든 버퍼를 비우고 기반 파일을 닫습니다.
3.2.13. 내부 타입 (Internal types)
인터프리터가 내부적으로 사용하는 몇 가지 타입이 사용자에게 노출됩니다. 그 정의는 향후 인터프리터 버전에서 바뀔 수 있지만, 완전성을 위해 여기서 언급합니다.
3.2.13.1. 코드 객체 (Code objects)
코드 객체는 바이트 컴파일된(byte-compiled) 실행 가능한 Python 코드, 즉 바이트코드를 나타냅니다. 코드 객체와 함수 객체의 차이는 함수 객체가 함수의 전역(정의된 모듈)에 대한 명시적 참조를 포함하는 반면 코드 객체는 컨텍스트를 포함하지 않는다는 것입니다. 또한 기본 인수 값은 코드 객체가 아니라 함수 객체에 저장됩니다(런타임에 계산된 값을 나타내므로). 함수 객체와 달리 코드 객체는 불변이며 변경 가능한 객체에 대한 참조(직접 또는 간접)를 포함하지 않습니다.
3.2.13.1.1. 특수 읽기 전용 속성 (Special read-only attributes)
| Attribute | Meaning |
|---|---|
| codeobject.co_name | 함수 이름 |
| codeobject.co_qualname | 완전히 정규화된 함수 이름. Added in version 3.11. |
| codeobject.co_argcount | 함수가 가진 위치 매개변수의 총 수(위치 전용 매개변수와 기본값을 가진 매개변수 포함). |
| codeobject.co_posonlyargcount | 함수가 가진 위치 전용 매개변수의 수(기본값을 가진 인수 포함). |
| codeobject.co_kwonlyargcount | 함수가 가진 키워드 전용 매개변수의 수(기본값을 가진 인수 포함). |
| codeobject.co_nlocals | 함수가 사용하는 지역 변수의 수(매개변수 포함). |
| codeobject.co_varnames | 함수의 지역 변수 이름을 포함하는 tuple(매개변수 이름으로 시작). |
| codeobject.co_cellvars | 함수 내부의 중첩 스코프 중 적어도 하나에서 참조되는 지역 변수 이름을 포함하는 tuple. |
| codeobject.co_freevars | 중첩 스코프가 바깥 스코프에서 참조하는 자유(클로저) 변수의 이름을 포함하는 tuple. function.__closure__도 참조. Note: 전역·내장 이름에 대한 참조는 포함되지 않습니다. |
| codeobject.co_code | 함수의 바이트코드 명령 시퀀스를 나타내는 문자열. |
| codeobject.co_consts | 함수의 바이트코드가 사용하는 리터럴을 포함하는 tuple. |
| codeobject.co_names | 함수의 바이트코드가 사용하는 이름을 포함하는 tuple. |
| codeobject.co_filename | 코드가 컴파일된 파일의 이름. |
| codeobject.co_firstlineno | 함수의 첫 줄의 줄 번호. |
| codeobject.co_lnotab | 바이트코드 오프셋에서 줄 번호로의 매핑을 인코딩하는 문자열. 자세한 내용은 인터프리터의 소스 코드 참조. Deprecated since version 3.12: 코드 객체의 이 속성은 더 이상 사용되지 않으며 Python 3.15에서 제거될 수 있습니다. |
| codeobject.co_stacksize | 코드 객체에 필요한 스택 크기. |
| codeobject.co_flags | 인터프리터에 대한 여러 플래그를 인코딩하는 integer. |
co_flags에 대해 다음 플래그 비트가 정의됩니다: 함수가 *arguments 구문을 사용해 임의 개수의 위치 인수를 받으면 비트 0x04가 설정되고, 함수가 **keywords 구문을 사용해 임의 키워드 인수를 받으면 비트 0x08이 설정되며, 함수가 제너레이터이면 비트 0x20이 설정됩니다. 존재할 수 있는 각 플래그의 의미에 대한 자세한 내용은 Code Objects Bit Flags 참조.
향후 기능 선언(예: from __future__ import division)도 co_flags의 비트를 사용해 코드 객체가 특정 기능을 사용해 컴파일되었는지 나타냅니다. compiler_flag 참조.
co_flags의 다른 비트는 내부 사용을 위해 예약되어 있습니다.
코드 객체가 함수를 나타내고 docstring이 있으면 co_flags에 CO_HAS_DOCSTRING 비트가 설정되고 co_consts의 첫 번째 항목은 함수의 docstring입니다.
3.2.13.1.2. 코드 객체의 메서드 (Methods on code objects)
codeobject.co_positions()
코드 객체의 각 바이트코드 명령의 소스 코드 위치에 대한 반복 가능 객체를 반환합니다.
반복자는 (start_line, end_line, start_column, end_column)을 포함하는 tuple들을 반환합니다. i-th 튜플은 i-th 코드 단위로 컴파일된 소스 코드의 위치에 대응합니다. 열 정보는 주어진 소스 줄의 0-인덱스 utf-8 바이트 오프셋입니다.
이 위치 정보는 없을 수 있습니다. 이런 경우(완전하지 않은 목록):
-Xno_debug_ranges로 인터프리터 실행.-Xno_debug_ranges를 사용하는 동안 컴파일된 pyc 파일 로드.- 인공 명령에 대응하는 위치 튜플.
- 구현 특정 한계로 표현할 수 없는 줄·열 번호.
이런 일이 발생하면 튜플 요소의 일부 또는 전부가 None일 수 있습니다. Added in version 3.11.
Note
이 기능은 코드 객체에 열 위치를 저장해야 하므로 컴파일된 Python 파일의 디스크 사용량이나 인터프리터 메모리 사용량이 약간 증가할 수 있습니다. 추가 정보 저장을 피하거나 추가 트레이스백 정보 인쇄를 비활성화하려면 -X no_debug_ranges 명령줄 플래그나 PYTHONNODEBUGRANGES 환경 변수를 사용할 수 있습니다.
codeobject.co_lines()
연속된 바이트코드 범위에 대한 정보를 산출하는 반복자를 반환합니다. 각 항목은 (start, end, lineno) tuple입니다:
start(anint)는 바이트코드 범위의 시작 오프셋(포함)을 나타냅니다.end(anint)는 바이트코드 범위의 끝 오프셋(제외)을 나타냅니다.lineno는 바이트코드 범위의 줄 번호를 나타내는int이거나, 주어진 범위의 바이트코드에 줄 번호가 없으면None입니다.
산출된 항목은 다음 속성들을 가집니다:
- 첫 번째 산출 범위는
start가 0입니다. (start, end)범위는 비감소하고 연속적입니다. 즉 어떤tuple쌍에 대해서도 두 번째의start는 첫 번째의end와 같습니다.- 어떤 범위도 역행하지 않습니다. 모든 쌍에 대해
end >= start입니다. - 마지막
tuple은end가 바이트코드의 크기와 같습니다.
start == end인 너비 0 범위는 허용됩니다. 너비 0 범위는 소스 코드에 존재하지만 바이트코드 컴파일러가 제거한 줄에 사용됩니다. Added in version 3.10.
See also
PEP 626 - Precise line numbers for debugging and other tools.
co_lines() 메서드를 도입한 PEP.
codeobject.replace(**kwargs)
지정된 필드에 대해 새 값으로 코드 객체의 복사본을 반환합니다.
코드 객체는 제네릭 함수 copy.replace()도 지원합니다. Added in version 3.8.
3.2.13.2. 프레임 객체 (Frame objects)
프레임 객체는 실행 프레임을 나타냅니다. 이들은 traceback 객체에서 발생할 수 있고, 등록된 트레이스 함수에도 전달됩니다.
3.2.13.2.1. 특수 읽기 전용 속성 (Special read-only attributes)
| Attribute | Meaning |
|---|---|
| frame.f_back | 이전 스택 프레임(호출자 쪽)을 가리키거나, 이것이 맨 아래 스택 프레임이면 None. |
| frame.f_code | 이 프레임에서 실행 중인 코드 객체. 이 속성에 접근하면 인수 obj와 "f_code"로 감사 이벤트 object.__getattr__을 발생시킵니다. |
| frame.f_locals | 프레임이 지역 변수를 조회하는 데 사용하는 매핑. 프레임이 최적화된 스코프를 참조하면 write-through 프록시 객체를 반환할 수 있습니다. Changed in version 3.13: 최적화된 스코프에 대해 프록시를 반환합니다. |
| frame.f_globals | 프레임이 전역 변수를 조회하는 데 사용하는 딕셔너리. |
| frame.f_builtins | 프레임이 내장(본질) 이름을 조회하는 데 사용하는 딕셔너리. |
| frame.f_lasti | 프레임 객체의 "정밀 명령(precise instruction)"(코드 객체의 바이트코드 문자열에 대한 인덱스). |
| frame.f_generator | 이 프레임을 소유하는 제너레이터 또는 코루틴 객체, 프레임이 일반 함수이면 None. Added in version 3.14. |
3.2.13.2.2. 특수 쓰기 가능 속성 (Special writable attributes)
| Attribute | Meaning |
|---|---|
| frame.f_trace | None이 아니면 코드 실행 중 다양한 이벤트에 대해 호출되는 함수(디버거가 사용). 보통 각 새 소스 줄마다 이벤트가 발생합니다(f_trace_lines 참조). |
| frame.f_trace_lines | 이 속성을 False로 설정하면 각 소스 줄에 대해 추적 이벤트 발생을 비활성화합니다. |
| frame.f_trace_opcodes | 이 속성을 True로 설정하면 per-opcode 이벤트를 요청할 수 있습니다. 트레이스 함수가 발생시킨 예외가 추적 중인 함수로 빠져나가면 정의되지 않은 인터프리터 동작이 발생할 수 있다는 점에 주의하세요. |
| frame.f_lineno | 프레임의 현재 줄 번호 — 트레이스 함수 안에서 이 값을 쓰면 주어진 줄로 점프합니다(맨 아래 프레임에서만). 디버거는 이 속성에 쓰는 것으로 Jump 명령(aka Set Next Statement)을 구현할 수 있습니다. |
3.2.13.2.3. 프레임 객체 메서드 (Frame object methods)
프레임 객체는 하나의 메서드를 지원합니다:
frame.clear()
이 메서드는 프레임이 보유한 지역 변수에 대한 모든 참조를 지웁니다. 또한 프레임이 제너레이터에 속했으면 제너레이터가 최종화됩니다. 이는 프레임 객체를 포함하는 참조 순환을 끊는 데 도움이 됩니다(예: 예외를 잡고 그 traceback을 나중에 사용하기 위해 저장할 때).
프레임이 현재 실행 중이거나 일시 중단되면 RuntimeError가 발생합니다. Added in version 3.4.
Changed in version 3.13: 일시 중단된 프레임을 지우려고 하면 RuntimeError가 발생합니다(실행 중인 프레임의 경우 항상 그랬습니다).
3.2.13.3. 트레이스백 객체 (Traceback objects)
트레이스백 객체는 예외의 스택 트레이스를 나타냅니다. 트레이스백 객체는 예외가 발생할 때 암시적으로 만들어지며, types.TracebackType을 호출해 명시적으로 만들 수도 있습니다.
Changed in version 3.7: 트레이스백 객체는 이제 Python 코드에서 명시적으로 인스턴스화할 수 있습니다.
암시적으로 만들어진 트레이스백의 경우, 예외 핸들러 검색이 실행 스택을 풀 때 각 풀린 수준에서 트레이스백 객체가 현재 트레이스백 앞에 삽입됩니다. 예외 핸들러에 들어가면 스택 트레이스가 프로그램에 제공됩니다. (The try statement 섹션 참조.) 이는 sys.exc_info()가 반환하는 튜플의 세 번째 항목으로, 그리고 잡힌 예외의 __traceback__ 속성으로 접근할 수 있습니다.
프로그램에 적절한 핸들러가 없으면 스택 트레이스가 (보기 좋게 형식화되어) 표준 오류 스트림에 기록됩니다. 인터프리터가 대화형이면 sys.last_traceback으로 사용자에게도 제공됩니다.
명시적으로 만들어진 트레이스백의 경우, tb_next 속성을 어떻게 연결해 전체 스택 트레이스를 형성할지 결정하는 것은 트레이스백의 생성자에게 달려 있습니다.
특수 읽기 전용 속성:
| Attribute | Meaning |
|---|---|
| traceback.tb_frame | 현재 수준의 실행 프레임을 가리킵니다. 이 속성에 접근하면 인수 obj와 "tb_frame"으로 감사 이벤트 object.__getattr__을 발생시킵니다. |
| traceback.tb_lineno | 예외가 발생한 줄 번호를 제공합니다. |
| traceback.tb_lasti | "정밀 명령"을 나타냅니다. |
예외가 일치하는 except 절이 없거나 finally 절이 있는 try 문에서 발생한 경우, 트레이스백의 줄 번호와 마지막 명령이 프레임 객체의 줄 번호와 다를 수 있습니다.
traceback.tb_next
특수 쓰기 가능 속성 tb_next는 스택 트레이스의 다음 수준(예외가 발생한 프레임 쪽)이거나, 다음 수준이 없으면 None입니다.
Changed in version 3.7: 이 속성은 이제 쓰기 가능합니다.
3.2.13.4. 슬라이스 객체 (Slice objects)
슬라이스 객체는 __getitem__() 메서드를 위한 슬라이스를 나타내는 데 사용됩니다. 내장 slice() 함수로도 만들어집니다.
특수 읽기 전용 속성: start는 하한, stop은 상한, step은 스텝 값이며, 생략되면 각각 None입니다. 이 속성들은 어떤 타입이든 될 수 있습니다.
슬라이스 객체는 하나의 메서드를 지원합니다:
slice.indices(self, length)
이 메서드는 단일 정수 인수 length를 받아* length 항목의 시퀀스에 적용하면 슬라이스 객체가 설명할 슬라이스에 대한 정보를 계산합니다. 세 정수의 튜플을 반환하는데, 각각 슬라이스의 start와 stop 인덱스, step 또는 보폭 길이입니다. 누락되거나 경계를 벗어난 인덱스는 일반 슬라이스와 일관된 방식으로 처리됩니다.
3.2.13.5. 정적 메서드 객체 (Static method objects)
정적 메서드 객체는 위에서 설명한 함수 객체를 메서드 객체로 변환하는 것을 무력화하는 방법을 제공합니다. 정적 메서드 객체는 다른 어떤 객체, 보통 사용자 정의 메서드 객체 주변의 래퍼입니다. 정적 메서드 객체가 클래스나 클래스 인스턴스에서 가져와지면 실제로 반환되는 것은 래핑된 객체이며, 이는 추가 변환의 대상이 아닙니다. 정적 메서드 객체도 호출 가능합니다. 정적 메서드 객체는 내장 staticmethod() 생성자로 만들어집니다.
3.2.13.6. 클래스 메서드 객체 (Class method objects)
클래스 메서드 객체는 정적 메서드 객체처럼 다른 객체 주변의 래퍼로서, 클래스와 클래스 인스턴스에서 그 객체가 가져와지는 방식을 변경합니다. 그러한 검색 시 클래스 메서드 객체의 동작은 위 "instance methods" 아래에 설명되어 있습니다. 클래스 메서드 객체는 내장 classmethod() 생성자로 만들어집니다.
3.3. 특수 메서드 이름 (Special method names)
클래스는 특수 이름을 가진 메서드를 정의함으로써 특수 구문(산술 연산 또는 첨자·슬라이싱 같은)이 호출하는 특정 연산을 구현할 수 있습니다. 이것이 Python의 연산자 오버로딩(operator overloading) 접근 방식으로, 클래스가 언어 연산자에 대해 자신만의 동작을 정의할 수 있게 합니다. 예를 들어 클래스가 __getitem__()이라는 이름의 메서드를 정의하고 x가 이 클래스의 인스턴스라면 x[i]는 type(x).__getitem__(x, i)와 대략 동등합니다. 언급된 경우를 제외하고, 적절한 메서드가 정의되지 않았을 때 연산을 실행하려고 하면 예외(보통 AttributeError 또는 TypeError)가 발생합니다.
특수 메서드를 None으로 설정하면 해당 연산을 사용할 수 없음을 나타냅니다. 예를 들어 클래스가 __iter__()를 None으로 설정하면 클래스는 반복 불가능하므로, 인스턴스에 iter()를 호출하면 TypeError가 발생합니다(__getitem__()로 대체되지 않음). [2]
내장 타입을 에뮬레이션하는 클래스를 구현할 때는, 에뮬레이션이 모델링하는 객체에 대해 합리적인 정도로만 구현하는 것이 중요합니다. 예를 들어 어떤 시퀀스는 개별 요소 검색에는 잘 작동할 수 있지만 슬라이스 추출은 합리적이지 않을 수 있습니다. (한 예는 W3C의 Document Object Model의 NodeList 인터페이스입니다.)
3.3.1. 기본 사용자화 (Basic customization)
object.new(cls[, ...])
클래스 cls의 새 인스턴스를 만들기 위해 호출됩니다. __new__()는 정적 메서드(그렇게 선언할 필요 없도록 특별 취급됨)로, 인스턴스가 요청된 클래스를 첫 번째 인수로 받습니다. 나머지 인수는 객체 생성자 표현식(클래스 호출)에 전달된 인수들입니다. __new__()의 반환 값은 새 객체 인스턴스(보통 cls의 인스턴스)여야 합니다.
일반적인 구현은 적절한 인수로 super().__new__(cls[, ...])를 사용해 슈퍼클래스의 __new__() 메서드를 호출함으로써 클래스의 새 인스턴스를 만든 다음, 필요에 따라 반환하기 전에 새로 만든 인스턴스를 수정합니다.
객체 생성 중 __new__()가 호출되어 cls의 인스턴스를 반환하면, 새 인스턴스의 __init__() 메서드가 __init__(self[, ...])처럼 호출됩니다. 여기서 self는 새 인스턴스이고 나머지 인수는 객체 생성자에 전달된 것과 같습니다.
__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)
인스턴스가 파괴되려고 할 때 호출됩니다. finalizer 또는 (부적절하게) destructor라고도 합니다. 기반 클래스에 __del__() 메서드가 있으면 파생 클래스의 __del__() 메서드(있다면)는 인스턴스의 기반 클래스 부분의 올바른 삭제를 보장하기 위해 그것을 명시적으로 호출해야 합니다.
__del__() 메서드가 새 참조를 만들어 인스턴스의 파괴를 연기하는 것이 가능하지만(권장되지는 않음!) 이는 객체 *부활(resurrection)*이라고 합니다. 부활된 객체가 파괴되려고 할 때 __del__()이 두 번째로 호출되는지는 구현에 따라 다릅니다. 현재 CPython 구현은 한 번만 호출합니다.
인터프리터가 종료될 때 여전히 존재하는 객체에 대해 __del__() 메서드가 호출된다는 보장은 없습니다. weakref.finalize는 객체가 가비지 컬렉션될 때 호출될 정리 함수를 등록하는 간단한 방법을 제공합니다.
Note
del x는 x.__del__()을 직접 호출하지 않습니다. 전자는 x의 참조 횟수를 1 감소시키고, 후자는 x의 참조 횟수가 0에 도달할 때만 호출됩니다.
CPython implementation detail: 참조 순환은 객체의 참조 횟수가 0으로 가는 것을 막을 수 있습니다. 이 경우 순환은 나중에 순환 가비지 컬렉터가 감지하고 삭제합니다. 참조 순환의 흔한 원인은 예외가 지역 변수에 잡힌 경우입니다. 그러면 프레임의 지역이 예외를 참조하고, 예외는 자신의 트레이스백을 참조하며, 트레이스백은 트레이스에 잡힌 모든 프레임의 지역을 참조합니다.
See also
gc 모듈 문서.
Warning
__del__() 메서드가 호출되는 불안정한 상황 때문에, 실행 중 발생하는 예외는 무시되고 대신 sys.stderr에 경고가 출력됩니다. 특히:
__del__()은 임의 코드가 실행 중일 때 호출될 수 있으며, 임의 스레드에서도 가능합니다. __del__()이 락을 잡거나 다른 차단 리소스를 호출해야 하면, __del__()을 실행하기 위해 중단된 코드가 이미 그 리소스를 잡고 있을 수 있어 교착 상태가 발생할 수 있습니다.
__del__()은 인터프리터 종료 중에 실행될 수 있습니다. 결과적으로 접근해야 하는 전역 변수(다른 모듈 포함)가 이미 삭제되거나 None으로 설정되었을 수 있습니다. Python은 단일 밑줄로 시작하는 이름의 전역이 다른 전역보다 먼저 그 모듈에서 삭제됨을 보장합니다. 그러한 전역에 대한 다른 참조가 없으면 __del__() 메서드가 호출될 때 가져온 모듈이 여전히 사용 가능함을 보장하는 데 도움이 될 수 있습니다.
object.repr(self)
repr() 내장 함수가 객체의 "공식" 문자열 표현을 계산하기 위해 호출합니다. 가능하면 이는 (적절한 환경이 주어졌을 때) 같은 값을 가진 객체를 재현하는 데 사용될 수 있는 유효한 Python 표현식처럼 보여야 합니다. 이것이 가능하지 않으면 <...some useful description...> 형태의 문자열을 반환해야 합니다. 반환 값은 문자열 객체여야 합니다. 클래스가 __repr__()은 정의하지만 __str__()은 정의하지 않으면, 그 클래스 인스턴스의 "비공식적" 문자열 표현이 필요할 때도 __repr__()이 사용됩니다.
이것은 보통 디버깅에 사용되므로 표현이 정보가 풍부하고 모호하지 않은 것이 중요합니다. 기본 구현은 object 클래스 자체가 제공합니다.
object.str(self)
str(object), 기본 __format__() 구현, 내장 함수 print()가 객체의 "비공식적" 또는 보기 좋게 인쇄 가능한 문자열 표현을 계산하기 위해 호출합니다. 반환 값은 str 객체여야 합니다.
이 메서드는 object.__repr__()과 달리 __str__()이 유효한 Python 표현식을 반환할 것이라는 기대가 없다는 점에서 다릅니다. 더 편리하거나 간결한 표현을 사용할 수 있습니다.
내장 타입 object가 정의하는 기본 구현은 object.__repr__()을 호출합니다.
object.bytes(self)
bytes가 객체의 바이트 문자열 표현을 계산하기 위해 호출합니다. bytes 객체를 반환해야 합니다. object 클래스 자체는 이 메서드를 제공하지 않습니다.
object.format(self, format_spec)
format() 내장 함수, 그리고 그 연장으로 형식 문자열 리터럴과 str.format() 메서드의 평가가 객체의 "형식화된" 문자열 표현을 만들기 위해 호출합니다. format_spec 인수는 원하는 형식 옵션의 설명을 포함하는 문자열입니다. format_spec 인수의 해석은 __format__()을 구현하는 타입에 달려 있지만, 대부분의 클래스는 내장 타입 중 하나에 형식화를 위임하거나 유사한 형식 옵션 구문을 사용합니다.
표준 형식 구문에 대한 설명은 Format specification mini-language 참조.
반환 값은 문자열 객체여야 합니다.
object 클래스의 기본 구현은 빈 format_spec 문자열이 주어져야 합니다. __str__()에 위임합니다.
Changed in version 3.4: object 자신의 format 메서드는 비어 있지 않은 문자열이 전달되면 TypeError를 발생시킵니다.
Changed in version 3.7: object.__format__(x, '')은 이제 format(str(x), '')이 아니라 str(x)와 동등합니다.
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<y는 x.__lt__(y), x<=y는 x.__le__(y), x==y는 x.__eq__(y), x!=y는 x.__ne__(y), x>y는 x.__gt__(y), x>=y는 x.__ge__(y)를 호출합니다.
풍부 비교 메서드는 주어진 인수 쌍에 대해 연산을 구현하지 않으면 싱글턴 NotImplemented를 반환할 수 있습니다. 관례상 성공적인 비교에는 False와 True가 반환됩니다. 하지만 이 메서드들은 어떤 값이든 반환할 수 있으므로, 비교 연산자가 불리언 컨텍스트(예: if 문의 조건)에서 사용되면 Python은 그 값에 bool()을 호출해 결과가 참인지 거짓인지 결정합니다.
기본적으로 object는 is를 사용해 __eq__()을 구현하며, 거짓 비교의 경우 NotImplemented를 반환합니다: True if x is y else NotImplemented. __ne__()의 경우 기본적으로 __eq__()에 위임하고 결과가 NotImplemented가 아니면 결과를 반전합니다. 비교 연산자나 기본 구현 사이에 다른 내포된 관계는 없습니다. 예를 들어 (x<y or x==y)의 참이 x<=y를 내포하지 않습니다. 단일 루트 연산에서 순서 연산을 자동 생성하려면 @functools.total_ordering 참조.
기본적으로 object 클래스는 Value comparisons와 일관된 구현을 제공합니다. 동등 비교는 객체 정체성에 따라 비교하고, 순서 비교는 TypeError를 발생시킵니다. 각 기본 메서드는 이러한 결과를 직접 생성할 수도 있고 NotImplemented를 반환할 수도 있습니다.
사용자 지정 비교 연산을 지원하고 딕셔너리 키로 사용할 수 있는 해시 가능 객체를 만드는 것에 대한 중요한 주의사항은 __hash__() 문단 참조.
이 메서드들의 인수 교환 변형은 없습니다(왼쪽 인수가 연산을 지원하지 않지만 오른쪽 인수가 지원할 때 사용되는). 대신 __lt__()과 __gt__()은 서로의 반사( reflection)이고, __le__()과 __ge__()은 서로의 반사이며, __eq__()과 __ne__()은 자기 자신의 반사입니다. 피연산자의 타입이 다르고 오른쪽 피연산자의 타입이 왼쪽 피연산자 타입의 직접 또는 간접 하위 클래스이면 오른쪽 피연산자의 반사 메서드가 우선하고, 그렇지 않으면 왼쪽 피연산자의 메서드가 우선합니다. 가상 하위 클래스화(virtual subclassing)는 고려되지 않습니다.
적절한 메서드가 NotImplemented 외의 값을 반환하지 않으면 ==와 != 연산자는 각각 is와 is not으로 대체됩니다.
object.hash(self)
내장 함수 hash()와 set, frozenset, dict를 포함한 해시 컬렉션의 멤버에 대한 연산에 의해 호출됩니다. __hash__() 메서드는 정수를 반환해야 합니다. 유일한 필수 속성은 같게 비교되는 객체가 같은 해시 값을 가진다는 것입니다. 비교에 참여하는 객체의 구성요소의 해시 값을 튜플로 패킹하고 튜플을 해싱하여 섞는 것이 권장됩니다. 예:
def __hash__(self):
return hash((self.name, self.nick, self.color))
Note
hash()는 객체의 사용자 정의 __hash__() 메서드가 반환한 값을 Py_ssize_t 크기로 잘라냅니다. 이는 보통 64비트 빌드에서 8바이트, 32비트 빌드에서 4바이트입니다. 객체의 __hash__()이 다른 비트 크기의 빌드에서 상호 운용해야 하면, 지원하는 모든 빌드에서 너비를 확인하세요. 쉬운 방법은 python -c "import sys; print(sys.hash_info.width)"입니다.
클래스가 __eq__() 메서드를 정의하지 않으면 __hash__() 연산도 정의해서는 안 됩니다. __eq__()은 정의하지만 __hash__()은 정의하지 않으면 그 인스턴스는 해시 가능 컬렉션의 항목으로 사용할 수 없습니다. 클래스가 변경 가능한 객체를 정의하고 __eq__() 메서드를 구현하면 __hash__()을 구현해서는 안 됩니다. 해시 가능 컬렉션의 구현이 키의 해시 값이 불변임을 요구하기 때문입니다(객체의 해시 값이 변하면 잘못된 해시 버킷에 있게 됩니다).
사용자 정의 클래스는 기본적으로 __eq__()과 __hash__() 메서드를 가집니다(object 클래스에서 상속). 이들을 사용하면 모든 객체는 (자기 자신과를 제외하고) 같지 않게 비교되고, x.__hash__()은 x == y가 x is y와 hash(x) == hash(y) 둘 다를 함의하도록 적절한 값을 반환합니다.
__eq__()을 오버라이드하고 __hash__()을 정의하지 않는 클래스는 __hash__()이 암시적으로 None으로 설정됩니다. 클래스의 __hash__() 메서드가 None이면 프로그램이 해시 값을 가져오려고 할 때 그 클래스의 인스턴스는 적절한 TypeError를 발생시키고, isinstance(obj, collections.abc.Hashable)을 확인할 때 올바르게 해시 불가능으로 식별됩니다.
__eq__()을 오버라이드하는 클래스가 부모 클래스의 __hash__() 구현을 유지해야 하면 __hash__ = <ParentClass>.__hash__로 설정하여 인터프리터에 명시적으로 알려야 합니다.
__eq__()을 오버라이드하지 않는 클래스가 해시 지원을 억제하려면 클래스 정의에 __hash__ = None을 포함해야 합니다. TypeError를 명시적으로 발생시키는 자신만의 __hash__()을 정의하는 클래스는 isinstance(obj, collections.abc.Hashable) 호출에 의해 잘못 해시 가능으로 식별될 것입니다.
Note
기본적으로 str과 bytes 객체의 __hash__() 값은 예측할 수 없는 임의 값으로 "염처리(salted)"됩니다. 개별 Python 프로세스 내에서는 일정하게 유지되지만, Python의 반복 호출 사이에서는 예측할 수 없습니다.
이것은 dict 삽입의 최악의 경우 성능 O(n2) 복잡성을 악용하는 신중히 선택된 입력으로 인한 서비스 거부에 대한 보호를 제공하기 위한 것입니다. 자세한 내용은 https://ocert.org/advisories/ocert-2011-003.html 참조.
해시 값 변경은 집합의 반복 순서에 영향을 줍니다. Python은 이 순서에 대해 보장한 적이 없습니다(그리고 일반적으로 32비트와 64비트 빌드 사이에서 다릅니다).
PYTHONHASHSEED도 참조.
Changed in version 3.3: 해시 무작위화가 기본적으로 활성화되었습니다.
object.bool(self)
참 값 테스트와 내장 연산 bool()을 구현하기 위해 호출됩니다. False 또는 True를 반환해야 합니다. 이 메서드가 정의되지 않으면 __len__()이 정의되어 있다면 그것이 호출되고, 그 결과가 0이 아니면 객체가 참으로 간주됩니다. 클래스가 __len__()과 __bool__() 둘 다 정의하지 않으면(object 클래스 자체가 그럼) 모든 인스턴스가 참으로 간주됩니다.
3.3.2. 속성 접근 사용자화 (Customizing attribute access)
클래스 인스턴스에 대한 속성 접근(x.name의 사용, 할당 또는 삭제)의 의미를 사용자화하기 위해 다음 메서드들을 정의할 수 있습니다.
object.getattr(self, name)
기본 속성 접근이 AttributeError로 실패할 때 호출됩니다(__getattribute__()이 name이 인스턴스 속성도 아니고 self의 클래스 트리의 속성도 아니기 때문에 AttributeError를 발생시키거나; name 속성의 __get__()이 AttributeError를 발생시키기 때문에). 이 메서드는 (계산된) 속성 값을 반환하거나 AttributeError 예외를 발생시켜야 합니다. object 클래스 자체는 이 메서드를 제공하지 않습니다.
일반 메커니즘으로 속성이 발견되면 __getattr__()은 호출되지 않는다는 점에 주의하세요. (이것은 __getattr__()과 __setattr__() 사이의 의도된 비대칭입니다.) 이는 효율성 이유와, 그렇지 않으면 __getattr__()이 인스턴스의 다른 속성에 접근할 방법이 없기 때문입니다. 최소한 인스턴스 변수에 대해서는 인스턴스 속성 딕셔너리에 어떤 값도 넣지 않고(대신 다른 객체에 넣고) 완전한 제어를 할 수 있다는 점에 주의하세요. 속성 접근에 대한 완전한 제어를 실제로 얻는 방법은 아래 __getattribute__() 메서드 참조.
object.getattribute(self, name)
클래스 인스턴스에 대한 속성 접근을 구현하기 위해 무조건 호출됩니다. 클래스가 __getattr__()도 정의하면, __getattribute__()이 명시적으로 호출하거나 AttributeError를 발생시키지 않는 한 후자는 호출되지 않습니다. 이 메서드는 (계산된) 속성 값을 반환하거나 AttributeError 예외를 발생시켜야 합니다. 이 메서드에서 무한 재귀를 피하기 위해, 구현은 필요한 속성에 접근할 때 항상 같은 이름의 기반 클래스 메서드를 호출해야 합니다. 예: object.__getattribute__(self, name).
Note
언어 구문이나 내장 함수를 통한 암시적 호출의 결과로 특수 메서드를 조회할 때는 이 메서드가 여전히 우회될 수 있습니다. Special method lookup 참조.
특정 민감한 속성 접근에 대해 인수 obj와 name으로 감사 이벤트 object.__getattr__을 발생시킵니다.
object.setattr(self, name, value)
속성 할당이 시도될 때 호출됩니다. 일반 메커니즘(즉 인스턴스 딕셔너리에 값 저장) 대신 호출됩니다. name은 속성 이름, value는 그것에 할당할 값입니다.
__setattr__()이 인스턴스 속성에 할당하려면 같은 이름의 기반 클래스 메서드를 호출해야 합니다. 예: object.__setattr__(self, name, value).
특정 민감한 속성 할당에 대해 인수 obj, name, value로 감사 이벤트 object.__setattr__을 발생시킵니다.
object.delattr(self, name)
할당 대신 속성 삭제에 대해 __setattr__()과 같습니다. del obj.name이 객체에 의미가 있을 때만 구현해야 합니다.
특정 민감한 속성 삭제에 대해 인수 obj와 name으로 감사 이벤트 object.__delattr__을 발생시킵니다.
object.dir(self)
객체에 dir()이 호출될 때 호출됩니다. 반복 가능 객체를 반환해야 합니다. dir()은 반환된 반복 가능 객체를 리스트로 변환하고 정렬합니다.
3.3.2.1. 모듈 속성 접근 사용자화 (Customizing module attribute access)
module.getattr()
module.dir()
특수 이름 __getattr__과 __dir__은 모듈 속성으로의 접근을 사용자화하는 데도 사용될 수 있습니다. 모듈 수준의 __getattr__ 함수는 속성 이름인 하나의 인수를 받아 계산된 값을 반환하거나 AttributeError를 발생시켜야 합니다. 모듈 객체에서 속성이 일반 조회(즉 object.__getattribute__())로 발견되지 않으면, AttributeError를 발생시키기 전에 모듈 __dict__에서 __getattr__이 검색됩니다. 발견되면 속성 이름으로 호출되고 결과가 반환됩니다.
__dir__ 함수는 인수를 받지 않아야 하고, 모듈에서 접근 가능한 이름을 나타내는 문자열의 반복 가능 객체를 반환해야 합니다. 이 함수가 있으면 모듈에 대한 표준 dir() 검색을 오버라이드합니다.
module.class
모듈 동작(속성, 프로퍼티 등 설정)의 더 세밀한 사용자화를 위해 모듈 객체의 __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}...')
super().__setattr__(attr, value)
sys.modules[__name__].__class__ = VerboseModule
Note
모듈 __getattr__을 정의하고 모듈 __class__를 설정하는 것은 속성 접근 구문을 사용한 조회에만 영향을 줍니다. 모듈 전역에 직접 접근하는 것(모듈 내부의 코드든, 모듈의 전역 딕셔너리에 대한 참조를 통해서든)은 영향을 받지 않습니다.
Changed in version 3.5: __class__ 모듈 속성은 이제 쓰기 가능합니다.
Added in version 3.7: __getattr__과 __dir__ 모듈 속성.
See also
PEP 562 - Module getattr and dir
모듈의 __getattr__과 __dir__ 함수를 설명합니다.
3.3.2.2. 디스크립터 구현 (Implementing Descriptors)
다음 메서드는 메서드를 포함하는 클래스(소위 디스크립터(descriptor) 클래스)의 인스턴스가 소유자(owner) 클래스에 나타날 때만 적용됩니다(디스크립터는 소유자의 클래스 딕셔너리 또는 그 부모 중 하나의 클래스 딕셔너리에 있어야 합니다). 아래 예에서 "the attribute"는 소유자 클래스의 __dict__에서 프로퍼티의 키인 이름을 가진 속성을 가리킵니다. object 클래스 자체는 이러한 프로토콜 중 어떤 것도 구현하지 않습니다.
object.get(self, instance, owner=None)
소유자 클래스의 속성(클래스 속성 접근) 또는 그 클래스의 인스턴스의 속성(인스턴스 속성 접근)을 얻기 위해 호출됩니다. 선택적 owner 인수는 소유자 클래스이고, instance는 속성이 접근된 인스턴스, 또는 속성이 owner를 통해 접근될 때 None입니다.
이 메서드는 계산된 속성 값을 반환하거나 AttributeError 예외를 발생시켜야 합니다.
PEP 252은 __get__()이 하나 또는 두 개의 인수로 호출 가능하도록 지정합니다. Python 자신의 내장 디스크립터는 이 사양을 지원합니다. 하지만 일부 타사 도구가 두 인수를 모두 요구하는 디스크립터를 가질 가능성이 있습니다. Python 자신의 __getattribute__() 구현은 필요 여부와 관계없이 항상 두 인수를 모두 전달합니다.
object.set(self, instance, value)
소유자 클래스의 인스턴스 instance의 속성을 새 값 value로 설정하기 위해 호출됩니다.
__set__() 또는 __delete__()을 추가하면 디스크립터의 종류가 "데이터 디스크립터(data descriptor)"로 바뀐다는 점에 주의하세요. 자세한 내용은 Invoking Descriptors 참조.
object.delete(self, instance)
소유자 클래스의 인스턴스 instance의 속성을 삭제하기 위해 호출됩니다.
디스크립터의 인스턴스는 __objclass__ 속성도 가질 수 있습니다:
object.objclass
__objclass__ 속성은 inspect 모듈에 의해 이 객체가 정의된 클래스를 지정하는 것으로 해석됩니다(적절히 설정하면 동적 클래스 속성의 런타임 내부 검사에 도움이 될 수 있습니다). 호출 가능 객체의 경우 주어진 타입(또는 하위 클래스)의 인스턴스가 첫 번째 위치 인수로 기대되거나 요구됨을 나타낼 수 있습니다(예: CPython은 C로 구현된 바인딩되지 않은 메서드에 대해 이 속성을 설정합니다).
3.3.2.3. 디스크립터 호출 (Invoking Descriptors)
일반적으로 디스크립터는 "바인딩 동작"을 가진 객체 속성으로, 그 속성 접근이 디스크립터 프로토콜의 메서드인 __get__(), __set__(), __delete__()에 의해 오버라이드되었습니다. 이 메서드 중 하나라도 객체에 정의되어 있으면 디스크립터라고 합니다.
속성 접근의 기본 동작은 객체의 딕셔너리에서 속성을 얻거나, 설정하거나, 삭제하는 것입니다. 예를 들어 a.x는 a.__dict__['x']에서 시작해 type(a).__dict__['x']로, 메타클래스를 제외한 type(a)의 기반 클래스를 거쳐 계속되는 조회 체인을 가집니다.
하지만 조회된 값이 디스크립터 메서드 중 하나를 정의하는 객체라면, Python은 기본 동작을 오버라이드하고 대신 디스크립터 메서드를 호출할 수 있습니다. 우선순위 체인에서 이것이 발생하는 위치는 어떤 디스크립터 메서드가 정의되었고 어떻게 호출되었는지에 따라 다릅니다.
디스크립터 호출의 시작점은 바인딩 a.x입니다. 인수가 어떻게 조립되는지는 a에 따라 다릅니다:
직접 호출 (Direct Call)
가장 간단하고 가장 드문 호출은 사용자 코드가 디스크립터 메서드를 직접 호출하는 경우입니다: x.__get__(a).
인스턴스 바인딩 (Instance Binding)
객체 인스턴스에 바인딩하면 a.x는 호출로 변환됩니다: type(a).__dict__['x'].__get__(a, type(a)).
클래스 바인딩 (Class Binding)
클래스에 바인딩하면 A.x는 호출로 변환됩니다: A.__dict__['x'].__get__(None, A).
슈퍼 바인딩 (Super Binding)
super(A, a).x 같은 점 조회는 a.__class__.__mro__에서 A 다음의 기반 클래스 B를 검색한 다음 B.__dict__['x'].__get__(a, A)를 반환합니다. 디스크립터가 아니면 x는 변경 없이 반환됩니다.
인스턴스 바인딩의 경우 디스크립터 호출의 우선순위는 어떤 디스크립터 메서드가 정의되었는지에 따라 다릅니다. 디스크립터는 __get__(), __set__(), __delete__()의 어떤 조합이든 정의할 수 있습니다. __get__()을 정의하지 않으면 객체의 인스턴스 딕셔너리에 값이 없는 한 속성에 접근하면 디스크립터 객체 자체가 반환됩니다. 디스크립터가 __set__() 및/또는 __delete__()을 정의하면 데이터 디스크립터이고, 둘 다 정의하지 않으면 비-데이터 디스크립터입니다. 일반적으로 데이터 디스크립터는 __get__()과 __set__()을 모두 정의하고, 비-데이터 디스크립터는 __get__() 메서드만 가집니다. __get__()과 __set__()(및/또는 __delete__())이 정의된 데이터 디스크립터는 항상 인스턴스 딕셔너리의 재정의를 오버라이드합니다. 대조적으로 비-데이터 디스크립터는 인스턴스에 의해 오버라이드될 수 있습니다.
(@staticmethod와 @classmethod로 데코레이트된 것을 포함한) Python 메서드는 비-데이터 디스크립터로 구현됩니다. 따라서 인스턴스는 메서드를 재정의하고 오버라이드할 수 있습니다. 이는 개별 인스턴스가 같은 클래스의 다른 인스턴스와 다른 동작을 획득할 수 있게 합니다.
@property 데코레이터는 데이터 디스크립터로 구현됩니다. 따라서 인스턴스는 프로퍼티의 동작을 오버라이드할 수 없습니다.
3.3.2.4. slots
*slots*을 사용하면 데이터 멤버(프로퍼티처럼)를 명시적으로 선언하고 __dict__와 *weakref의 생성을 거부할 수 있습니다(slots*에 명시적으로 선언되거나 부모에서 사용 가능하지 않은 한).
__dict__를 사용하는 것에 비해 절약되는 공간은 상당할 수 있습니다. 속성 조회 속도도 크게 향상될 수 있습니다.
object.slots
이 클래스 변수에는 인스턴스가 사용하는 변수 이름이 있는 문자열, 반복 가능 객체 또는 문자열 시퀀스를 할당할 수 있습니다. *slots*는 선언된 변수에 공간을 예약하고 각 인스턴스에 대한 __dict__와 *weakref*의 자동 생성을 방지합니다.
slots 사용에 대한 주의사항:
*slots*이 없는 클래스에서 상속할 때 인스턴스의 __dict__와 weakref 속성은 항상 접근 가능합니다.
__dict__ 변수가 없으면 인스턴스는 slots 정의에 나열되지 않은 새 변수를 할당받을 수 없습니다. 나열되지 않은 변수 이름에 할당하려고 하면 AttributeError가 발생합니다. 새 변수의 동적 할당이 원하면 slots 선언의 문자열 시퀀스에 '__dict__'를 추가하세요.
각 인스턴스에 weakref 변수가 없으면 *slots*을 정의하는 클래스는 인스턴스에 대한 weak references를 지원하지 않습니다. 약한 참조 지원이 필요하면 slots 선언의 문자열 시퀀스에 '__weakref__'를 추가하세요.
*slots*은 각 변수 이름에 대해 디스크립터를 만들어 클래스 수준에서 구현됩니다. 결과적으로 클래스 속성을 사용해 *slots*이 정의한 인스턴스 변수의 기본값을 설정할 수 없습니다. 그렇지 않으면 클래스 속성이 디스크립터 할당을 덮어쓰게 됩니다.
slots 선언의 동작은 정의된 클래스에 국한되지 않습니다. 부모에 선언된 *slots*은 자식 클래스에서 사용할 수 있습니다. 하지만 하위 클래스가 *slots*도 정의하지 않는 한(추가 슬롯의 이름만 포함해야 함) 하위 클래스의 인스턴스는 __dict__와 *weakref*를 얻습니다.
클래스가 기반 클래스에서도 정의된 슬롯을 정의하면 기반 클래스 슬롯이 정의한 인스턴스 변수는 접근할 수 없습니다(기반 클래스에서 디스크립터를 직접 검색하는 것 제외). 이는 프로그램의 의미를 정의되지 않게 만듭니다. 향후 이를 방지하는 검사가 추가될 수 있습니다.
int, bytes, tuple 같은 "variable-length built-in type"에서 파생된 클래스에 비어 있지 않은 *slots*이 정의되면 TypeError가 발생합니다.
문자열이 아닌 어떤 반복 가능 객체든 *slots*에 할당할 수 있습니다.
*slots*을 할당하는 데 dictionary를 사용하면 딕셔너리 키가 슬롯 이름으로 사용됩니다. 딕셔너리 값은 inspect.getdoc()이 인식하고 help()의 출력에 표시되는 속성별 docstring을 제공하는 데 사용할 수 있습니다.
__class__ 할당은 두 클래스가 같은 *slots*을 가질 때만 동작합니다.
여러 슬롯이 있는 부모 클래스와의 다중 상속을 사용할 수 있지만, 슬롯이 만든 속성을 가진 부모는 하나만 허용됩니다(다른 기반은 빈 슬롯 레이아웃을 가져야 합니다). 위반하면 TypeError가 발생합니다.
*slots*에 반복자를 사용하면 반복자의 각 값에 대해 디스크립터가 만들어집니다. 하지만 slots 속성은 빈 반복자가 됩니다.
3.3.3. 클래스 생성 사용자화 (Customizing class creation)
클래스가 다른 클래스에서 상속할 때마다 부모 클래스에서 __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__은 아무것도 하지 않지만 인수와 함께 호출되면 오류를 발생시킵니다.
Note
메타클래스 힌트 metaclass는 나머지 type 메커니즘에 의해 소비되며, __init_subclass__ 구현에 결코 전달되지 않습니다. 실제 메타클래스(명시적 힌트가 아닌)는 type(cls)로 접근할 수 있습니다.
Added in version 3.6.
클래스가 생성될 때 type.__new__()은 클래스 변수를 검사하고 __set_name__() 훅이 있는 것들에 콜백을 만듭니다.
object.set_name(self, owner, name)
소유 클래스 owner가 만들어질 때 자동으로 호출됩니다. 객체가 그 클래스에서 name에 할당되었습니다:
class A:
x = C() # Automatically calls: x.__set_name__(A, 'x')
클래스가 생성된 후에 클래스 변수가 할당되면 __set_name__()은 자동으로 호출되지 않습니다. 필요하면 __set_name__()을 직접 호출할 수 있습니다:
class A:
pass
c = C()
A.x = c # The hook is not called
c.__set_name__(A, 'x') # Manually invoke the hook
자세한 내용은 Creating the class object 참조. Added in version 3.6.
3.3.3.1. 메타클래스 (Metaclasses)
기본적으로 클래스는 type()으로 구성됩니다. 클래스 본문은 새 네임스페이스에서 실행되고 클래스 이름은 type(name, bases, namespace)의 결과에 로컬로 바인딩됩니다.
클래스 생성 과정은 클래스 정의 줄에 metaclass 키워드 인수를 전달하거나, 그러한 인수를 포함한 기존 클래스에서 상속함으로써 사용자화할 수 있습니다. 다음 예에서 MyClass와 MySubclass 모두 Meta의 인스턴스입니다:
class Meta(type):
pass
class MyClass(metaclass=Meta):
pass
class MySubclass(MyClass):
pass
클래스 정의에 지정된 다른 키워드 인수는 아래 설명하는 모든 메타클래스 연산에 전달됩니다.
클래스 정의가 실행될 때 다음 단계가 발생합니다:
MRO 항목이 해석됩니다.
적절한 메타클래스가 결정됩니다.
클래스 네임스페이스가 준비됩니다.
클래스 본문이 실행됩니다.
클래스 객체가 생성됩니다.
3.3.3.2. MRO 항목 해석 (Resolving MRO entries)
object.mro_entries(self, bases)
클래스 정의에 나타나는 기반이 type의 인스턴스가 아니면 기반에서 __mro_entries__() 메서드가 검색됩니다. __mro_entries__() 메서드가 발견되면 클래스를 만들 때 기반이 __mro_entries__() 호출의 결과로 대체됩니다. 메서드는 원래 기반 튜플을 bases 매개변수로 전달받아 호출되며, 기반 대신 사용될 클래스들의 튜플을 반환해야 합니다. 반환된 튜플은 비어 있을 수 있습니다. 이 경우 원래 기반은 무시됩니다.
See also
types.resolve_bases()
type의 인스턴스가 아닌 기반을 동적으로 해석합니다.
types.get_original_bases()
__mro_entries__()에 의한 수정 이전의 클래스의 "원래 기반"을 가져옵니다.
PEP 560
typing 모듈과 제네릭 타입의 핵심 지원.
3.3.3.3. 적절한 메타클래스 결정 (Determining the appropriate metaclass)
클래스 정의에 대한 적절한 메타클래스는 다음과 같이 결정됩니다:
기반도 명시적 메타클래스도 없으면 type()이 사용됩니다.
명시적 메타클래스가 주어지고 type()의 인스턴스가 아니면 메타클래스로 직접 사용됩니다.
type()의 인스턴스가 명시적 메타클래스로 주어지거나 기반이 정의되면 가장 파생된 메타클래스가 사용됩니다.
가장 파생된 메타클래스는 명시적으로 지정된 메타클래스(있다면)와 모든 지정된 기반 클래스의 메타클래스(즉 type(cls))에서 선택됩니다. 가장 파생된 메타클래스는 이 모든 후보 메타클래스의 하위 타입인 것입니다. 어떤 후보 메타클래스도 그 기준을 충족하지 않으면 클래스 정의는 TypeError로 실패합니다.
3.3.3.4. 클래스 네임스페이스 준비 (Preparing the class namespace)
적절한 메타클래스가 식별되면 클래스 네임스페이스가 준비됩니다. 메타클래스에 __prepare__ 속성이 있으면 namespace = metaclass.__prepare__(name, bases, **kwds)로 호출됩니다(추가 키워드 인수가 있다면 클래스 정의에서 옴). __prepare__ 메서드는 classmethod로 구현되어야 합니다. __prepare__가 반환한 네임스페이스는 __new__에 전달되지만, 최종 클래스 객체가 만들어질 때 네임스페이스는 새 dict로 복사됩니다.
메타클래스에 __prepare__ 속성이 없으면 클래스 네임스페이스는 빈 순서 매핑으로 초기화됩니다.
See also
PEP 3115 - Metaclasses in Python 3000
__prepare__ 네임스페이스 훅을 도입했습니다.
3.3.3.5. 클래스 본문 실행 (Executing the class body)
클래스 본문은 (대략) exec(body, globals(), namespace)로 실행됩니다. 일반 exec() 호출과의 핵심 차이는 어휘 스코핑이 클래스 본문(메서드 포함)이 클래스 정의가 함수 안에서 발생할 때 현재 및 바깥 스코프의 이름을 참조할 수 있게 한다는 것입니다.
하지만 클래스 정의가 함수 안에서 발생하더라도 클래스 안에 정의된 메서드는 클래스 스코프에서 정의된 이름을 볼 수 없습니다. 클래스 변수는 인스턴스 또는 클래스 메서드의 첫 번째 매개변수, 또는 다음 섹션에서 설명하는 암시적 어휘 스코프 __class__ 참조를 통해 접근해야 합니다.
3.3.3.6. 클래스 객체 생성 (Creating the class object)
클래스 네임스페이스가 클래스 본문 실행으로 채워지면 클래스 객체가 metaclass(name, bases, namespace, **kwds)를 호출해 만들어집니다(여기 전달된 추가 키워드는 __prepare__에 전달된 것과 같습니다).
이 클래스 객체는 super()의 0-인수 형태가 참조하는 것입니다. __class__는 클래스 본문의 어떤 메서드가 __class__나 super를 참조하면 컴파일러가 만드는 암시적 클로저 참조입니다. 이를 통해 super()의 0-인수 형태가 어휘 스코핑에 기반해 정의 중인 클래스를 올바르게 식별할 수 있으며, 현재 호출을 만드는 데 사용된 클래스나 인스턴스는 메서드에 전달된 첫 번째 인수에 기반해 식별됩니다.
CPython implementation detail: CPython 3.6 이상에서 __class__ 셀은 클래스 네임스페이스의 __classcell__ 항목으로 메타클래스에 전달됩니다. 클래스가 올바르게 초기화되려면 이 항목이 있을 때 type.__new__ 호출로 전파되어야 합니다. 그렇게 하지 않으면 Python 3.8에서 RuntimeError가 발생합니다.
기본 메타클래스 type을 사용하거나 궁극적으로 type.__new__을 호출하는 메타클래스를 사용할 때, 클래스 객체 생성 후 다음 추가 사용자화 단계가 호출됩니다:
type.__new__ 메서드가 클래스 네임스페이스에서 __set_name__() 메서드를 정의하는 모든 속성을 수집합니다.
그 __set_name__ 메서드들이 정의 중인 클래스와 해당 특정 속성의 할당된 이름으로 호출됩니다.
__init_subclass__() 훅이 메서드 해석 순서에서 새 클래스의 직접 부모에서 호출됩니다.
클래스 객체가 생성된 후 클래스 정의에 포함된(있다면) 클래스 데코레이터에 전달되고, 결과 객체는 정의된 클래스로 로컬 네임스페이스에 바인딩됩니다.
type.__new__으로 새 클래스가 만들어질 때 네임스페이스 매개변수로 제공된 객체는 새 순서 매핑으로 복사되고 원래 객체는 버려집니다. 새 복사본은 읽기 전용 프록시로 감싸지며, 이는 클래스 객체의 __dict__ 속성이 됩니다.
See also
PEP 3135 - New super
암시적 __class__ 클로저 참조를 설명합니다.
3.3.3.7. 메타클래스의 용도 (Uses for metaclasses)
메타클래스의 잠재적 용도는 무궁무진합니다. 탐구된 아이디어에는 enum, 로깅, 인터페이스 검사, 자동 위임, 자동 프로퍼티 생성, 프록시, 프레임워크, 자동 리소스 잠금/동기화가 포함됩니다.
3.3.4. 인스턴스 및 하위 클래스 검사 사용자화 (Customizing instance and subclass checks)
다음 메서드는 isinstance()과 issubclass() 내장 함수의 기본 동작을 오버라이드하는 데 사용됩니다.
특히 메타클래스 abc.ABCMeta는 추상 기반 클래스(ABC)를 어떤 클래스나 타입(내장 타입 포함), 다른 ABC에 "가상 기반 클래스"로 추가할 수 있도록 이 메서드들을 구현합니다.
type.instancecheck(self, instance)
instance가 class의 (직접 또는 간접) 인스턴스로 간주되어야 하면 참을 반환합니다. 정의되면 isinstance(instance, class)를 구현하기 위해 호출됩니다.
type.subclasscheck(self, subclass)
subclass가 class의 (직접 또는 간접) 하위 클래스로 간주되어야 하면 참을 반환합니다. 정의되면 issubclass(subclass, class)를 구현하기 위해 호출됩니다.
이 메서드들은 클래스의 타입(메타클래스)에서 조회된다는 점에 주의하세요. 실제 클래스의 클래스 메서드로 정의할 수 없습니다. 이는 인스턴스에서 호출되는 특수 메서드의 조회와 일관됩니다. 다만 이 경우 인스턴스가 곧 클래스입니다.
See also
PEP 3119 - Introducing Abstract Base Classes
__instancecheck__()과 __subclasscheck__()을 통한 isinstance()과 issubclass() 동작 사용자화 사양을 포함하며, 언어에 추상 기반 클래스(abc 모듈 참조)를 추가하는 맥락에서 이 기능의 동기를 제공합니다.
3.3.5. 제네릭 타입 에뮬레이션 (Emulating generic types)
타입 주석을 사용할 때 Python의 대괄호 표기를 사용해 제네릭 타입을 매개변수화(parameterize) 하는 것이 유용한 경우가 많습니다. 예를 들어 주석 list[int]는 모든 요소가 int 타입인 list를 나타내는 데 사용될 수 있습니다.
See also
PEP 484 - Type Hints
Python의 타입 주석 프레임워크를 도입합니다.
Generic Alias Types
매개변수화된 제네릭 클래스를 나타내는 객체 문서.
Generics, user-defined generics and typing.Generic
런타임에 매개변수화될 수 있고 정적 타입 검사기가 이해할 수 있는 제네릭 클래스를 구현하는 방법 문서.
클래스는 일반적으로 특수 클래스 메서드 __class_getitem__()을 정의하는 경우에만 매개변수화될 수 있습니다.
classmethod object.class_getitem(cls, key)
key에서 찾은 타입 인수로 제네릭 클래스의 특수화를 나타내는 객체를 반환합니다.
클래스에 정의되면 __class_getitem__()은 자동으로 클래스 메서드입니다. 따라서 정의할 때 @classmethod로 데코레이트할 필요가 없습니다.
3.3.5.1. __class_getitem__의 목적 (The purpose of class_getitem)
__class_getitem__()의 목적은 표준 라이브러리 제네릭 클래스의 런타임 매개변수화를 허용해 이러한 클래스에 타입 힌트를 더 쉽게 적용하기 위한 것입니다.
런타임에 매개변수화될 수 있고 정적 타입 검사기가 이해할 수 있는 사용자 정의 제네릭 클래스를 구현하려면, 사용자는 이미 __class_getitem__()을 구현하는 표준 라이브러리 클래스에서 상속하거나, 자신만의 __class_getitem__() 구현을 가진 typing.Generic에서 상속해야 합니다.
표준 라이브러리 밖에서 정의된 클래스의 __class_getitem__() 사용자 정의 구현은 mypy 같은 타사 타입 검사기가 이해하지 못할 수 있습니다. 타입 힌팅 이외의 목적으로 어떤 클래스에서든 __class_getitem__()을 사용하는 것은 권장되지 않습니다.
3.3.5.2. class_getitem 대 getitem (class_getitem versus getitem)
보통 객체의 대괄호 첨자는 객체의 클래스에 정의된 __getitem__() 인스턴스 메서드를 호출합니다. 하지만 첨자를 당하는 객체가 그 자체로 클래스라면 클래스 메서드 __class_getitem__()이 대신 호출될 수 있습니다. __class_getitem__()은 제대로 정의되면 GenericAlias 객체를 반환해야 합니다.
obj[x] 표현식이 제시되면 Python 인터프리터는 __getitem__() 또는 __class_getitem__() 중 무엇을 호출해야 할지 결정하기 위해 대략 다음 과정을 따릅니다:
from inspect import isclass
def subscribe(obj, x):
"""Return the result of the expression 'obj[x]'"""
class_of_obj = type(obj)
# If the class of obj defines __getitem__,
# call class_of_obj.__getitem__(obj, x)
if hasattr(class_of_obj, '__getitem__'):
return class_of_obj.__getitem__(obj, x)
# Else, if obj is a class and defines __class_getitem__,
# call obj.__class_getitem__(x)
elif isclass(obj) and hasattr(obj, '__class_getitem__'):
return obj.__class_getitem__(x)
# Else, raise an exception
else:
raise TypeError(
f"'{class_of_obj.__name__}' object is not subscriptable"
)
Python에서 모든 클래스는 그 자체로 다른 클래스의 인스턴스입니다. 클래스의 클래스를 그 클래스의 메타클래스라고 하며, 대부분의 클래스는 type 클래스를 메타클래스로 가집니다. type은 __getitem__()을 정의하지 않으므로, list[int], dict[str, float], tuple[str, bytes] 같은 표현식은 모두 __class_getitem__()이 호출되는 결과를 낳습니다:
>>> # list has class "type" as its metaclass, like most classes:
>>> type(list)
<class 'type'>
>>> type(dict) == type(list) == type(tuple) == type(str) == type(bytes)
True
>>> # "list[int]" calls "list.__class_getitem__(int)"
>>> list[int]
list[int]
>>> # list.__class_getitem__ returns a GenericAlias object:
>>> type(list[int])
<class 'types.GenericAlias'>
하지만 클래스에 __getitem__()을 정의하는 사용자 정의 메타클래스가 있으면 클래스를 첨자 처리해도 다른 동작이 나올 수 있습니다. 이 예는 enum 모듈에서 찾을 수 있습니다:
>>> from enum import Enum
>>> class Menu(Enum):
... """A breakfast menu"""
... SPAM = 'spam'
... BACON = 'bacon'
...
>>> # Enum classes have a custom metaclass:
>>> type(Menu)
<class 'enum.EnumMeta'>
>>> # EnumMeta defines __getitem__,
>>> # so __class_getitem__ is not called,
>>> # and the result is not a GenericAlias object:
>>> Menu['SPAM']
<Menu.SPAM: 'spam'>
>>> type(Menu['SPAM'])
<enum 'Menu'>
See also
PEP 560 - Core Support for typing module and generic types
__class_getitem__()을 도입하고, 첨자가 __getitem__() 대신 __class_getitem__()을 호출하게 되는 경우를 설명합니다.
3.3.6. 호출 가능 객체 에뮬레이션 (Emulating callable objects)
object.call(self[, args...])
인스턴스가 함수로 "호출"될 때 호출됩니다. 이 메서드가 정의되면 x(arg1, arg2, ...)는 대략 type(x).__call__(x, arg1, ...)로 변환됩니다. object 클래스 자체는 이 메서드를 제공하지 않습니다.
3.3.7. 컨테이너 타입 에뮬레이션 (Emulating container types)
컨테이너 객체를 구현하기 위해 다음 메서드들을 정의할 수 있습니다. object 클래스 자체는 이 중 어떤 것도 제공하지 않습니다. 컨테이너는 보통 시퀀스(list나 tuple 같은) 또는 매핑(딕셔너리 같은)이지만 다른 컨테이너를 나타낼 수도 있습니다. 첫 번째 메서드 집합은 시퀀스나 매핑을 에뮬레이션하는 데 사용됩니다. 차이는 시퀀스의 경우 허용되는 키가 0 <= k < N(여기서 N은 시퀀스의 길이)인 정수 k 또는 항목 범위를 정의하는 slice 객체여야 한다는 것입니다. 또한 매핑은 Python 표준 dictionary 객체와 유사하게 동작하는 keys(), values(), items(), get(), clear(), setdefault(), pop(), popitem(), copy(), update() 메서드를 제공하는 것이 권장됩니다. collections.abc 모듈은 __getitem__(), __setitem__(), __delitem__(), keys()의 기본 집합에서 그러한 메서드를 만드는 데 도움이 되는 MutableMapping 추상 기반 클래스를 제공합니다.
변경 가능한 시퀀스는 Python 표준 list 객체처럼 append(), clear(), count(), extend(), index(), insert(), pop(), remove(), reverse() 메서드를 제공해야 합니다. 마지막으로 시퀀스 타입은 아래 설명하는 __add__(), __radd__(), __iadd__(), __mul__(), __rmul__(), __imul__() 메서드를 정의해 덧셈(연결을 의미)과 곱셈(반복을 의미)을 구현해야 합니다. 다른 수치 연산자는 정의해서는 안 됩니다.
매핑과 시퀀스 모두 in 연산자의 효율적인 사용을 허용하도록 __contains__() 메서드를 구현하는 것이 권장됩니다. 매핑의 경우 in은 매핑의 키를 검색해야 하고, 시퀀스의 경우 값을 검색해야 합니다. 또한 매핑과 시퀀스 모두 컨테이너를 통한 효율적인 반복을 허용하도록 __iter__() 메서드를 구현하는 것이 권장됩니다. 매핑의 경우 __iter__()은 객체의 키를 반복해야 하고, 시퀀스의 경우 값을 반복해야 합니다.
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인 정수여야 합니다. 반환 값은 NotImplemented일 수도 있으며, 이는 __length_hint__ 메서드가 아예 없는 것처럼 취급됩니다. 이 메서드는 순전히 최적화이며 정확성을 위해 결코 필요하지 않습니다. Added in version 3.4.
object.getitem(self, subscript)
첨자(subscription), 즉 self[subscript]를 구현하기 위해 호출됩니다. 구문에 대한 자세한 내용은 Subscriptions and slicings 참조.
__getitem__()을 통한 첨자를 지원하는 두 종류의 내장 객체가 있습니다:
시퀀스, 여기서 subscript(또는 index)는 정수 또는 slice 객체여야 합니다. slice 객체와 음수 인덱스 처리의 기대 동작은 시퀀스 문서 참조.
매핑, 여기서 subscript는 키라고도 합니다. 기대 동작은 매핑 문서 참조.
subscript가 부적절한 타입이면 __getitem__()은 TypeError를 발생시켜야 합니다. subscript가 부적절한 값이면 __getitem__()은 LookupError 또는 그 하위 클래스(시퀀스의 경우 IndexError, 매핑의 경우 KeyError)를 발생시켜야 합니다.
Note
슬라이싱은 __getitem__(), __setitem__(), __delitem__()이 처리합니다.
a[1:2] = b
같은 호출은
a[slice(1, 2, None)] = b
로 변환되는 식입니다. 누락된 슬라이스 항목은 항상 None으로 채워집니다.
Note
시퀀스 반복 프로토콜(예: for 루프에서 사용)은 시퀀스의 끝을 올바르게 감지하도록 불법 인덱스에 대해 IndexError가 발생하기를 기대합니다.
Note
클래스를 첨자 처리할 때는 __getitem__() 대신 특수 클래스 메서드 __class_getitem__()이 호출될 수 있습니다. 자세한 내용은 class_getitem versus getitem 참조.
object.setitem(self, key, value)
self[key]에 대한 할당을 구현하기 위해 호출됩니다. __getitem__()과 같은 주의사항이 적용됩니다. 객체가 키에 대한 값 변경을 지원하거나 새 키를 추가할 수 있는 매핑, 또는 요소를 교체할 수 있는 시퀀스에 대해서만 구현해야 합니다. 부적절한 key 값에 대해서는 __getitem__() 메서드와 같은 예외를 발생시켜야 합니다.
object.delitem(self, key)
self[key]의 삭제를 구현하기 위해 호출됩니다. __getitem__()과 같은 주의사항이 적용됩니다. 객체가 키 제거를 지원하는 매핑 또는 시퀀스에서 요소 제거를 지원하는 시퀀스에 대해서만 구현해야 합니다. 부적절한 key 값에 대해서는 __getitem__() 메서드와 같은 예외를 발생시켜야 합니다.
object.missing(self, key)
키가 딕셔너리에 없을 때 dict 하위 클래스에 대해 self[key]를 구현하기 위해 dict.__getitem__()이 호출합니다.
object.iter(self)
컨테이너에 반복자가 필요할 때 이 메서드가 호출됩니다. 이 메서드는 컨테이너의 모든 객체를 반복할 수 있는 새 반복자 객체를 반환해야 합니다. 매핑의 경우 컨테이너의 키를 반복해야 합니다.
object.reversed(self)
(있으면) reversed() 내장 함수가 역방향 반복을 구현하기 위해 호출합니다. 컨테이너의 모든 객체를 역순으로 반복하는 새 반복자 객체를 반환해야 합니다.
__reversed__() 메서드가 제공되지 않으면 reversed() 내장 함수는 시퀀스 프로토콜(__len__()과 __getitem__())을 사용하는 것으로 대체됩니다. 시퀀스 프로토콜을 지원하는 객체는 reversed()가 제공하는 것보다 효율적인 구현을 제공할 수 있을 때만 __reversed__()을 제공해야 합니다.
멤버십 테스트 연산자(in과 not in)는 보통 컨테이너를 통한 반복으로 구현됩니다. 하지만 컨테이너 객체는 객체가 반복 가능할 것을 요구하지 않는 더 효율적인 구현과 함께 다음 특수 메서드를 제공할 수 있습니다.
object.contains(self, item)
멤버십 테스트 연산자를 구현하기 위해 호출됩니다. item이 self에 있으면 참을, 그렇지 않으면 거짓을 반환해야 합니다. 매핑 객체의 경우 값이나 키-항목 쌍이 아니라 매핑의 키를 고려해야 합니다.
__contains__()을 정의하지 않는 객체의 경우 멤버십 테스트는 먼저 __iter__()을 통한 반복을 시도한 다음, __getitem__()을 통한 구식 시퀀스 반복 프로토콜을 시도합니다. 언어 참조의 이 섹션 참조.
3.3.8. 숫자 타입 에뮬레이션 (Emulating numeric types)
숫자 객체를 에뮬레이션하기 위해 다음 메서드들을 정의할 수 있습니다. 구현된 특정 종류의 숫자가 지원하지 않는 연산(예: 비-정수 숫자에 대한 비트 연산)에 대응하는 메서드는 정의하지 않은 채로 두어야 합니다.
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(), **, <<, >>, &, ^, |)을 구현하기 위해 호출됩니다. 예를 들어 __add__() 메서드를 가진 클래스의 인스턴스인 x로 표현식 x + y를 평가하려면 type(x).__add__(x, 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[, modulo])
object.rlshift(self, other)
object.rrshift(self, other)
object.rand(self, other)
object.rxor(self, other)
object.ror(self, other)
이 메서드들은 반사(교환)된 피연산자로 이항 산술 연산(+, -, *, @, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |)을 구현하기 위해 호출됩니다. 이 함수들은 피연산자의 타입이 다르고 왼쪽 피연산자가 해당 연산을 지원하지 않거나 [3] 오른쪽 피연산자의 클래스가 왼쪽 피연산자의 클래스에서 파생된 경우에만 호출됩니다. [4] 예를 들어 __rsub__() 메서드를 가진 클래스의 인스턴스인 y로 표현식 x - y를 평가하려면, type(x).__sub__(x, y)가 NotImplemented를 반환하거나 type(y)가 type(x)의 하위 클래스이면 type(y).__rsub__(y, x)가 호출됩니다. [5]
내장 pow() 함수의 세-인수 버전을 지원하려면 __rpow__()이 선택적 세 번째 인수를 받도록 정의해야 한다는 점에 주의하세요.
Changed in version 3.14: 세-인수 pow()가 이제 필요하면 __rpow__() 호출을 시도합니다. 이전에는 두-인수 pow()와 이항 거듭제곱 연산자에서만 호출되었습니다.
Note
오른쪽 피연산자의 타입이 왼쪽 피연산자 타입의 하위 클래스이고 그 하위 클래스가 연산에 대한 반사 메서드의 다른 구현을 제공하면, 이 메서드는 왼쪽 피연산자의 비-반사 메서드보다 먼저 호출됩니다. 이 동작은 하위 클래스가 조상의 연산을 오버라이드할 수 있게 합니다.
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)
이 메서드들은 확장 산술 할당(augmented arithmetic assignments) 연산(+=, -=, *=, @=, /=, //=, %=, **=, <<=, >>=, &=, ^=, |=)을 구현하기 위해 호출됩니다. 이 메서드들은 제자리(in-place)로 연산을 수행하고(self 수정) 결과(self일 수도 있고 아닐 수도 있음)를 반환해야 합니다. 특정 메서드가 정의되지 않았거나 그 메서드가 NotImplemented를 반환하면 확장 할당은 일반 메서드로 대체됩니다. 예를 들어 x가 __iadd__() 메서드를 가진 클래스의 인스턴스이면 x += y는 x = x.__iadd__(y)와 동등합니다. __iadd__()이 없거나 x.__iadd__(y)가 NotImplemented를 반환하면 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()을 구현하기 위해 호출되며, Python이 숫자 객체를 무손실로 정수 객체로 변환해야 할 때마다(슬라이싱이나 내장 bin(), hex(), oct() 함수 등) 호출됩니다. 이 메서드가 있으면 숫자 객체가 정수 타입임을 나타냅니다. 정수를 반환해야 합니다.
__int__(), __float__(), __complex__()이 정의되지 않으면 해당 내장 함수 int(), float(), complex()은 __index__()로 대체됩니다.
object.round(self[, ndigits])
object.trunc(self)
object.floor(self)
object.ceil(self)
내장 함수 round()와 math 함수 trunc(), floor(), ceil()을 구현하기 위해 호출됩니다. __round__()에 ndigits가 전달되지 않으면 이 메서드들은 모두 객체의 값을 Integral(보통 int)로 잘린 값을 반환해야 합니다.
Changed in version 3.14: int()은 더 이상 __trunc__() 메서드에 위임하지 않습니다.
3.3.9. With 문 컨텍스트 관리자 (With Statement Context Managers)
*컨텍스트 관리자(context manager)*는 with 문을 실행할 때 수립할 런타임 컨텍스트를 정의하는 객체입니다. 컨텍스트 관리자는 원하는 런타임 컨텍스트로의 진입과 이탈을 코드 블록 실행을 위해 처리합니다. 컨텍스트 관리자는 보통 with 문(The with statement 섹션 참조)으로 호출되지만, 메서드를 직접 호출해서도 사용할 수 있습니다.
컨텍스트 관리자의 일반적인 용도는 다양한 종류의 전역 상태 저장·복원, 리소스 잠금·잠금 해제, 열린 파일 닫기 등입니다.
컨텍스트 관리자에 대한 자세한 내용은 Context Manager Types 참조. object 클래스 자체는 컨텍스트 관리자 메서드를 제공하지 않습니다.
object.enter(self)
이 객체와 관련된 런타임 컨텍스트에 들어갑니다. with 문은 이 메서드의 반환 값을 문의 as 절에 지정된 대상(들)에 바인딩합니다(있다면).
object.exit(self, exc_type, exc_value, traceback)
이 객체와 관련된 런타임 컨텍스트에서 나갑니다. 매개변수는 컨텍스트를 나가게 한 예외를 설명합니다. 컨텍스트가 예외 없이 나가면 세 인수 모두 None입니다.
예외가 제공되고 메서드가 예외를 억제(즉 전파를 방지)하려면 참 값을 반환해야 합니다. 그렇지 않으면 예외는 이 메서드에서 나올 때 정상적으로 처리됩니다.
__exit__() 메서드는 전달된 예외를 다시 발생시키지 않아야 합니다. 이는 호출자의 책임입니다.
See also
PEP 343 - The "with" statement
Python with 문의 사양, 배경, 예.
3.3.10. 클래스 패턴 매칭에서 위치 인수 사용자화 (Customizing positional arguments in class pattern matching)
패턴에서 클래스 이름을 사용할 때 패턴의 위치 인수는 기본적으로 허용되지 않습니다. 즉 case MyClass(x, y)는 MyClass의 특별한 지원 없이는 일반적으로 유효하지 않습니다. 그런 종류의 패턴을 사용하려면 클래스가 match_args 속성을 정의해야 합니다.
object.match_args
이 클래스 변수에는 문자열 튜플을 할당할 수 있습니다. 이 클래스가 위치 인수가 있는 클래스 패턴에 사용되면 각 위치 인수는 *match_args*의 해당 값을 키워드로 사용해 키워드 인수로 변환됩니다. 이 속성이 없으면 ()로 설정한 것과 동등합니다.
예를 들어 MyClass.__match_args__가 ("left", "center", "right")이면 case MyClass(x, y)는 case MyClass(left=x, center=y)와 동등합니다. 패턴의 인수 수는 *match_args*의 요소 수보다 작거나 같아야 합니다. 더 크면 패턴 매칭 시도가 TypeError를 발생시킵니다.
Added in version 3.10.
See also
PEP 634 - Structural Pattern Matching
Python match 문의 사양.
3.3.11. 버퍼 타입 에뮬레이션 (Emulating buffer types)
버퍼 프로토콜은 Python 객체가 저수준 메모리 배열에 대한 효율적인 접근을 노출하는 방법을 제공합니다. 이 프로토콜은 bytes와 memoryview 같은 내장 타입으로 구현되며, 타사 라이브러리가 추가 버퍼 타입을 정의할 수 있습니다.
버퍼 타입은 보통 C로 구현되지만 Python에서 프로토콜을 구현하는 것도 가능합니다.
object.buffer(self, flags)
self에서 버퍼가 요청될 때(예: memoryview 생성자로) 호출됩니다. flags 인수는 요청된 버퍼의 종류를 나타내는 정수로, 예를 들어 반환된 버퍼가 읽기 전용인지 쓰기 가능인지에 영향을 줍니다. inspect.BufferFlags는 플래그를 해석하는 편리한 방법을 제공합니다. 메서드는 memoryview 객체를 반환해야 합니다.
Thread safety: free-threaded Python에서 구현은 내부 export 카운터를 원자 연산으로 관리해야 합니다. 메서드는 여러 스레드에서 동시에 호출되어도 안전해야 하며, 반환된 버퍼의 기반 데이터는 해당 __release_buffer__() 호출이 완료될 때까지 유효해야 합니다. 자세한 내용은 Thread safety for memoryview objects 참조.
object.release_buffer(self, buffer)
버퍼가 더 이상 필요하지 않을 때 호출됩니다. buffer 인수는 이전에 __buffer__()이 반환한 memoryview 객체입니다. 메서드는 버퍼와 연관된 모든 리소스를 해제해야 합니다. 이 메서드는 None을 반환해야 합니다.
Thread safety: free-threaded Python에서 export 카운터 감소는 원자 연산을 사용해야 합니다. 리소스 정리는 스레드 안전해야 합니다. 최종 해제가 다른 스레드의 동시 해제와 경합할 수 있기 때문입니다.
정리를 수행할 필요가 없는 버퍼 객체는 이 메서드를 구현할 필요가 없습니다.
Added in version 3.12.
See also
PEP 688 - Making the buffer protocol accessible in Python
Python __buffer__와 __release_buffer__ 메서드를 소개합니다.
collections.abc.Buffer
버퍼 타입을 위한 ABC.
3.3.12. 주석 (Annotations)
함수, 클래스, 모듈은 주석(annotations)을 포함할 수 있으며, 이는 기호에 정보(보통 타입 힌트)를 연관시키는 방법입니다.
object.annotations
이 속성은 객체에 대한 주석을 포함합니다. 지연 평가되므로 속성에 접근하면 임의 코드를 실행하고 예외를 발생시킬 수 있습니다. 평가가 성공하면 속성은 변수 이름에서 주석으로의 매핑인 딕셔너리로 설정됩니다.
Changed in version 3.14: 주석이 이제 지연 평가됩니다.
object.annotate(format)
주석 함수(annotate function). 속성/매개변수 이름을 그 주석 값에 매핑하는 새 딕셔너리 객체를 반환합니다.
주석 값을 제공할 형식을 지정하는 format 매개변수를 받습니다. annotationlib.Format 열거형의 멤버이거나, 열거형 멤버에 해당하는 값을 가진 정수여야 합니다.
주석 함수가 요청된 형식을 지원하지 않으면 NotImplementedError를 발생시켜야 합니다. 주석 함수는 항상 VALUE 형식을 지원해야 합니다. 이 형식으로 호출될 때 NotImplementedError()를 발생시켜서는 안 됩니다.
VALUE 형식으로 호출될 때 주석 함수는 NameError를 발생시킬 수 있습니다. 다른 형식을 요청하여 호출될 때는 NameError를 발생시켜서는 안 됩니다.
객체에 주석이 없으면 __annotate__은 빈 dict를 반환하는 함수로 설정하기보다는 None으로 설정하는 것이 바람직합니다(삭제할 수 없음).
Added in version 3.14.
See also
PEP 649 — Deferred evaluation of annotation using descriptors
주석의 지연 평가와 __annotate__ 함수를 소개합니다.
3.3.13. 특수 메서드 조회 (Special method lookup)
사용자 정의 클래스의 경우 특수 메서드의 암시적 호출은 객체의 타입에 정의된 경우에만 올바르게 동작한다는 보장이 있으며, 객체의 인스턴스 딕셔너리에 정의된 경우는 아닙니다. 그 동작이 다음 코드가 예외를 발생시키는 이유입니다:
>>> 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 함수에서 반환된 코루틴 객체는 어웨이터블입니다.
Note
types.coroutine()으로 데코레이트된 제너레이터에서 반환된 제너레이터 반복자 객체도 어웨이터블이지만 __await__()을 구현하지는 않습니다.
object.await(self)
반복자를 반환해야 합니다. 어웨이터블 객체를 구현하는 데 사용되어야 합니다. 예를 들어 asyncio.Future는 await 표현식과 호환되도록 이 메서드를 구현합니다. object 클래스 자체는 어웨이터블이 아니며 이 메서드를 제공하지 않습니다.
Note
언어는 __await__이 반환한 반복자가 산출하는 객체의 타입이나 값에 어떤 제한도 두지 않습니다. 이는 어웨이터블 객체를 관리할 비동기 실행 프레임워크(예: asyncio)의 구현에 특정하기 때문입니다.
Added in version 3.5.
See also
어웨이터블 객체에 대한 추가 정보는 PEP 492.
3.4.2. 코루틴 객체 (Coroutine Objects)
코루틴 객체는 어웨이터블 객체입니다. 코루틴의 실행은 __await__()을 호출하고 결과를 반복함으로써 제어할 수 있습니다. 코루틴이 실행을 끝내고 반환하면 반복자가 StopIteration을 발생시키고, 예외의 value 속성이 반환 값을 보유합니다. 코루틴이 예외를 발생시키면 반복자가 전파합니다. 코루틴은 처리되지 않은 StopIteration 예외를 직접 발생시켜서는 안 됩니다.
코루틴은 아래 나열된 메서드도 가지며, 이는 제너레이터의 메서드(Generator-iterator methods 참조)와 유사합니다. 하지만 제너레이터와 달리 코루틴은 반복을 직접 지원하지 않습니다.
코루틴은 각각 yield, send, 반환 값의 타입에 대해 제네릭입니다.
Changed in version 3.5.2: 코루틴을 두 번 이상 await하는 것은 RuntimeError입니다.
coroutine.send(value)
코루틴의 실행을 시작하거나 재개합니다. value가 None이면 __await__()이 반환한 반복자를 진행시키는 것과 동등합니다. value가 None이 아니면 이 메서드는 코루틴을 일시 중단시킨 반복자의 send() 메서드에 위임합니다. 결과(반환 값, StopIteration 또는 다른 예외)는 위에서 설명한 __await__() 반환 값을 반복할 때와 같습니다.
coroutine.throw(value)
coroutine.throw(type[, value[, traceback]])
코루틴에서 지정된 예외를 발생시킵니다. 이 메서드는 코루틴을 일시 중단시킨 반복자의 throw() 메서드에 위임합니다(그런 메서드가 있으면). 그렇지 않으면 일시 중단 지점에서 예외가 발생합니다. 결과(반환 값, StopIteration 또는 다른 예외)는 위에서 설명한 __await__() 반환 값을 반복할 때와 같습니다. 예외가 코루틴에서 잡히지 않으면 호출자에게 다시 전파됩니다.
Changed in version 3.12: 두 번째 시그니처 (type[, value[, traceback]])는 더 이상 사용되지 않으며 향후 Python 버전에서 제거될 수 있습니다.
coroutine.close()
코루틴이 스스로 정리하고 종료하도록 합니다. 코루틴이 일시 중단되어 있으면 이 메서드는 먼저 코루틴을 일시 중단시킨 반복자의 close() 메서드에 위임합니다(그런 메서드가 있으면). 그런 다음 일시 중단 지점에서 GeneratorExit를 발생시켜 코루틴이 즉시 스스로 정리하게 합니다. 마지막으로 코루틴은 시작된 적이 없어도 실행을 마친 것으로 표시됩니다.
코루틴 객체는 파괴되려고 할 때 위 과정을 사용해 자동으로 닫힙니다.
3.4.3. 비동기 반복자 (Asynchronous Iterators)
*비동기 반복자(asynchronous iterator)*는 __anext__ 메서드에서 비동기 코드를 호출할 수 있습니다.
비동기 반복자는 async for 문에서 사용될 수 있습니다.
object 클래스 자체는 이러한 메서드를 제공하지 않습니다.
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
Added in version 3.5.
Changed in version 3.7: Python 3.7 이전에는 __aiter__()이 비동기 반복자로 해석되는 어웨이터블을 반환할 수 있었습니다. Python 3.7부터 __aiter__()은 비동기 반복자 객체를 반환해야 합니다. 다른 것을 반환하면 TypeError 오류가 발생합니다.
3.4.4. 비동기 컨텍스트 관리자 (Asynchronous Context Managers)
*비동기 컨텍스트 관리자(asynchronous context manager)*는 __aenter__와 __aexit__ 메서드에서 실행을 일시 중단할 수 있는 컨텍스트 관리자입니다.
비동기 컨텍스트 관리자는 async with 문에서 사용될 수 있습니다.
object 클래스 자체는 이러한 메서드를 제공하지 않습니다.
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')
Added in version 3.5.
Footnotes
[1]
특정 통제된 조건에서 객체의 타입을 변경하는 것이 어떤 경우에는 가능합니다. 하지만 대체로 좋은 생각은 아닙니다. 잘못 처리되면 매우 이상한 동작으로 이어질 수 있기 때문입니다.
[2]
__hash__(), __iter__(), __reversed__(), __contains__(), __class_getitem__()와 __fspath__() 메서드는 이에 대한 특별 처리가 있습니다. 다른 것들은 여전히 TypeError를 발생시키지만, None이 호출 가능하지 않다는 동작에 의존해 그렇게 할 수 있습니다.
[3]
"지원하지 않는다"는 것은 클래스에 그런 메서드가 없거나 메서드가 NotImplemented를 반환한다는 뜻입니다. 오른쪽 피연산자의 반사 메서드로의 대체를 강제하려면 메서드를 None으로 설정하지 마세요. 그렇게 하면 반대로 그러한 대체를 명시적으로 차단하는 효과가 있습니다.
[4]
같은 타입의 피연산자의 경우 비-반사 메서드(예: __add__())가 실패하면 연산이 지원되지 않는 것으로 가정되므로 반사 메서드가 호출되지 않습니다.
[5]
오른쪽 피연산자의 타입이 왼쪽 피연산자 타입의 하위 클래스이면 반사 메서드가 우선하여 하위 클래스가 조상의 연산을 오버라이드할 수 있습니다.
더 알아보기 (Learn more)
Python 언어 참조의 다른 데이터 모델 관련 문서와 객체 지향 프로그래밍 개념을 참고하세요.