Python Language Reference > 4. Execution model

4.1. Structure of a program

Python 프로그램은 코드 블록으로 구성됩니다. 블록은 하나의 단위로 실행되는 Python 프로그램 텍스트 조각입니다. 다음은 모듈, 함수 본문 및 클래스 정의와 같은 블록입니다. 대화식으로 입력되는 각 명령은 블록입니다. 스크립트 파일(인터프리터에 표준 입력으로 제공되거나 인터프리터에 명령줄 인수로 지정된 파일)은 코드 블록입니다. 스크립트 명령(-c 옵션을 사용하여 인터프리터 명령줄에 지정된 명령)은 코드 블록입니다. -m 인수를 사용하여 명령줄에서 최상위 수준 스크립트(모듈 __main__)로 실행되는 모듈도 코드 블록입니다. 내장 함수 eval() 및 exec()에 전달되는 문자열 인수는 코드 블록입니다.

코드 블록은 실행 프레임에서 실행됩니다. 프레임에는 일부 관리 정보(디버깅에 사용됨)가 포함되어 있으며 코드 블록의 실행이 완료된 후 실행이 계속되는 위치와 방법을 결정합니다.

4.2. Naming and binding

4.2.1. Binding of names

이름은 개체를 나타냅니다. 이름은 이름 바인딩 작업을 통해 도입됩니다.

다음 구성은 이름을 바인드합니다:

  • 함수에 대한 공식 매개변수,
  • 클래스 정의,
  • 함수 정의,
  • 대입 표현,
  • 할당에서 발생하는 경우 식별자인 대상:
    • for 루프 헤더,
    • with 문, except 절, except* 절 또는 구조적 패턴 일치의 as-pattern에서 as 뒤에,
    • 구조적 패턴 일치의 캡처 패턴에서
  • import 문

from … import * 형식의 import 문은 밑줄로 시작하는 이름을 제외하고 가져온 모듈에 정의된 모든 이름을 바인딩합니다. 이 양식은 모듈 수준에서만 사용할 수 있습니다.

del 문에서 발생하는 대상도 이 목적을 위해 바인딩된 것으로 간주됩니다(실제 시맨틱은 이름을 바인딩 해제하는 것임).

각 할당 또는 가져오기 문은 클래스 또는 함수 정의에 의해 정의된 블록 내에서 또는 모듈 수준(최상위 코드 블록)에서 발생합니다.

이름이 블록에 바인딩되어 있으면 비지역 또는 전역으로 선언되지 않는 한 해당 블록의 지역 변수입니다. 이름이 모듈 수준에서 바인딩되면 전역 변수입니다. (모듈 코드 블록의 변수는 지역 변수와 전역 변수입니다.) 변수가 코드 블록에서 사용되지만 정의되지 않은 경우 자유 변수입니다.

프로그램 텍스트에 나오는 각 이름은 다음 이름 확인 규칙에 의해 설정된 해당 이름의 바인딩을 나타냅니다.

4.2.2. Resolution of names

범위는 블록 내에서 이름의 가시성을 정의합니다. 지역 변수가 블록에 정의된 경우 해당 범위에는 해당 블록이 포함됩니다. 함수 블록에서 정의가 발생하는 경우 포함된 블록이 이름에 대해 다른 바인딩을 도입하지 않는 한 범위는 정의 블록 내에 포함된 모든 블록으로 확장됩니다.

코드 블록에서 이름이 사용되면 가장 가까운 둘러싸는 범위를 사용하여 확인됩니다. 코드 블록에 표시되는 이러한 모든 범위 집합을 블록의 환경이라고 합니다.

이름을 전혀 찾을 수 없으면 NameError 예외가 발생합니다. 현재 범위가 함수 범위이고 이름이 사용된 지점에서 아직 값에 바인딩되지 않은 지역 변수를 이름이 참조하는 경우 UnboundLocalError 예외가 발생합니다. UnboundLocalError는 NameError의 하위 클래스입니다.

코드 블록 내 어디에서나 이름 바인딩 작업이 발생하면 블록 내에서 이름을 사용하는 모든 것이 현재 블록에 대한 참조로 처리됩니다. 이로 인해 바인딩되기 전에 블록 내에서 이름이 사용될 때 오류가 발생할 수 있습니다. 이 규칙은 미묘합니다. Python에는 선언이 없으며 이름 바인딩 작업이 코드 블록 내 어디에서나 발생할 수 있습니다. 코드 블록의 로컬 변수는 이름 바인딩 작업을 위해 블록의 전체 텍스트를 스캔하여 확인할 수 있습니다. 예제는 UnboundLocalError에 대한 FAQ 항목을 참조하십시오.

전역 문이 블록 내에서 발생하는 경우 문에 지정된 이름의 모든 사용은 최상위 네임스페이스에서 해당 이름의 바인딩을 참조합니다. 이름은 전역 네임스페이스, 즉 코드 블록을 포함하는 모듈의 네임스페이스와 내장 모듈의 네임스페이스인 내장 네임스페이스를 검색하여 최상위 네임스페이스에서 확인됩니다. 전역 네임스페이스가 먼저 검색됩니다. 거기에 이름이 없으면 builtins 네임스페이스가 검색됩니다. global 문은 나열된 이름의 모든 사용에 선행해야 합니다.

전역 문은 동일한 블록의 이름 바인딩 작업과 동일한 범위를 갖습니다. 자유 변수에 대한 가장 가까운 둘러싸는 범위에 전역 문이 포함된 경우 자유 변수는 전역으로 처리됩니다.

nonlocal 문은 해당 이름이 가장 가까운 둘러싸는 함수 범위에서 이전에 바인딩된 변수를 참조하도록 합니다. SyntaxError 는 주어진 이름이 둘러싸는 함수 범위에 존재하지 않으면 컴파일 타임에 발생합니다.

모듈의 네임스페이스는 모듈을 처음 가져올 때 자동으로 생성됩니다. 스크립트의 기본 모듈은 항상 __main__이라고 합니다.

exec() 및 eval()에 대한 클래스 정의 블록 및 인수는 이름 확인 컨텍스트에서 특별합니다. 클래스 정의는 이름을 사용하고 정의할 수 있는 실행 가능한 명령문입니다. 이러한 참조는 바인딩되지 않은 로컬 변수가 전역 네임스페이스에서 조회된다는 점을 제외하고 이름 확인에 대한 일반적인 규칙을 따릅니다. 클래스 정의의 네임스페이스는 클래스의 속성 사전이 됩니다. 클래스 블록에 정의된 이름의 범위는 클래스 블록으로 제한됩니다. 메서드의 코드 블록으로 확장되지 않습니다. 여기에는 함수 범위를 사용하여 구현되기 때문에 내포 및 생성기 표현식이 포함됩니다. 이는 다음이 실패함을 의미합니다.

class A:
    a = 42
    b = list(a + i for i in range(10))

4.2.3. Builtins and restricted execution

CPython 구현 세부 사항: 사용자는 __builtins__를 건드리면 안 됩니다. 엄격하게 구현 세부 사항입니다. builtins 네임스페이스의 값을 재정의하려는 사용자는 builtins 모듈을 가져와 해당 속성을 적절하게 수정해야 합니다.

코드 블록의 실행과 관련된 내장 네임스페이스는 실제로 전역 네임스페이스에서 __builtins__라는 이름을 검색하여 찾을 수 있습니다. 이것은 사전 또는 모듈이어야 합니다(후자의 경우 모듈의 사전이 사용됨). 기본적으로 __main__ 모듈에 있을 때 __builtins__는 내장 모듈 내장입니다. 다른 모듈에 있을 때 __builtins__는 내장 모듈 자체의 사전에 대한 별칭입니다.

4.2.4. Interaction with dynamic features

자유 변수의 이름 확인은 컴파일 타임이 아니라 런타임에 발생합니다. 즉, 다음 코드는 42를 인쇄합니다.

i = 10
def f():
    print(i)
i = 42
f()

eval() 및 exec() 함수는 이름을 확인하기 위한 전체 환경에 액세스할 수 없습니다. 호출자의 로컬 및 전역 네임스페이스에서 이름을 확인할 수 있습니다. 자유 변수는 가장 가까운 둘러싸는 네임스페이스에서 해결되지 않고 전역 네임스페이스에서 해결됩니다. exec() 및 eval() 함수에는 전역 및 로컬 이름 공간을 재정의하는 선택적 인수가 있습니다. 하나의 네임스페이스만 지정된 경우 둘 다에 사용됩니다.

4.3. Exceptions

예외는 오류 또는 기타 예외 조건을 처리하기 위해 코드 블록의 정상적인 제어 흐름에서 벗어나는 수단입니다. 오류가 감지된 지점에서 예외가 발생합니다. 주변 코드 블록 또는 오류가 발생한 코드 블록을 직간접적으로 호출한 코드 블록에 의해 처리될 수 있습니다.

Python 인터프리터는 런타임 오류(예: 0으로 나누기)를 감지하면 예외를 발생시킵니다. Python 프로그램은 raise 문을 사용하여 명시적으로 예외를 발생시킬 수도 있습니다. 예외 처리기는 try … except 문으로 지정됩니다. 이러한 문의 finally 절은 예외를 처리하지 않지만 이전 코드에서 예외가 발생했는지 여부에 관계없이 실행되는 정리 코드를 지정하는 데 사용할 수 있습니다.

파이썬은 오류 처리의 “종료” 모델을 사용합니다. 예외 처리기는 무슨 일이 일어났는지 알아내고 외부 수준에서 실행을 계속할 수 있지만 오류의 원인을 복구하고 실패한 작업을 다시 시도할 수는 없습니다(문제가 되는 조각을 다시 입력하는 경우 제외). 상단의 코드).

예외가 전혀 처리되지 않으면 인터프리터는 프로그램 실행을 종료하거나 대화형 메인 루프로 돌아갑니다. 두 경우 모두 예외가 SystemExit인 경우를 제외하고는 스택 트레이스백을 인쇄합니다.

예외는 클래스 인스턴스로 식별됩니다. except 절은 인스턴스의 클래스에 따라 선택됩니다. 인스턴스의 클래스 또는 가상이 아닌 기본 클래스를 참조해야 합니다. 인스턴스는 핸들러에서 수신할 수 있으며 예외 조건에 대한 추가 정보를 전달할 수 있습니다.

참고: 예외 메시지는 Python API의 일부가 아닙니다. 그 내용은 경고 없이 Python의 한 버전에서 다음 버전으로 변경될 수 있으며 여러 버전의 인터프리터에서 실행되는 코드에 의존해서는 안 됩니다.

또한 try 문 섹션에 있는 try 문 및 raise 문 섹션raise 문에 대한 설명을 참조하십시오.

Source: https://docs.python.org/3/reference/executionmodel.html

Python Language Reference > 3. Data model

3.1. Objects, values and types

객체는 데이터에 대한 Python의 추상화입니다. Python 프로그램의 모든 데이터는 객체 또는 객체 간의 관계로 표현됩니다. (어떤 의미에서 Von Neumann의 “저장 프로그램 컴퓨터” 모델에 따라 코드도 객체로 표현됩니다.)

모든 개체에는 ID, 유형 및 값이 있습니다. 개체의 ID는 일단 생성되면 절대 변경되지 않습니다. 메모리에 있는 개체의 주소로 생각할 수 있습니다. ‘is’ 연산자는 두 개체의 ID를 비교합니다. id() 함수는 ID를 나타내는 정수를 반환합니다.

CPython 구현 세부 정보: CPython의 경우 id(x)는 x가 저장된 메모리 주소입니다.

개체의 유형은 개체가 지원하는 작업(예: “길이가 있습니까?”)을 결정하고 해당 유형의 개체에 가능한 값을 정의합니다. type() 함수는 객체의 유형(객체 자체)을 반환합니다. ID와 마찬가지로 객체의 유형도 변경할 수 없습니다.

일부 개체의 값은 변경될 수 있습니다. 값이 변경될 수 있는 객체는 변경 가능하다고 합니다. 일단 생성되면 값을 변경할 수 없는 객체를 불변(immutable)이라고 합니다. (가변 객체에 대한 참조를 포함하는 불변 컨테이너 객체의 값은 후자의 값이 변경될 때 변경될 수 있습니다. 그러나 컨테이너는 컨테이너에 포함된 객체 컬렉션을 변경할 수 없기 때문에 여전히 불변으로 간주됩니다. 변경할 수 없는 값을 갖는 것과 같으며 더 미묘합니다.) 개체의 변경 가능성은 해당 유형에 따라 결정됩니다. 예를 들어 숫자, 문자열 및 튜플은 변경할 수 없지만 사전 및 목록은 변경할 수 있습니다.

개체는 명시적으로 소멸되지 않습니다. 그러나 도달할 수 없게 되면 가비지 수집될 수 있습니다. 구현은 가비지 수집을 연기하거나 완전히 생략할 수 있습니다. 아직 도달 가능한 개체가 수집되지 않는 한 가비지 수집이 구현되는 방식은 구현 품질의 문제입니다.

CPython 구현 세부 정보: CPython은 현재 순환적으로 연결된 가비지의 지연 감지(선택 사항)와 함께 참조 계산 방식을 사용합니다. 이 방식은 대부분의 객체가 도달할 수 없게 되는 즉시 수집하지만 순환 참조를 포함하는 가비지 수집을 보장하지는 않습니다. 순환 가비지 수집 제어에 대한 정보는 gc 모듈의 문서를 참조하십시오. 다른 구현은 다르게 작동하며 CPython은 변경될 수 있습니다. 개체에 도달할 수 없게 되면 개체의 즉각적인 종료에 의존하지 마십시오(따라서 항상 파일을 명시적으로 닫아야 함).

구현의 추적 또는 디버깅 기능을 사용하면 일반적으로 수집 가능한 개체를 활성 상태로 유지할 수 있습니다. 또한 ‘try…except’ 문으로 예외를 포착하면 개체를 활성 상태로 유지할 수 있습니다.

일부 개체에는 열려 있는 파일이나 창과 같은 “외부” 리소스에 대한 참조가 포함되어 있습니다. 객체가 가비지 수집될 때 이러한 리소스가 해제되는 것으로 이해되지만 가비지 수집이 발생한다고 보장할 수 없기 때문에 이러한 객체는 일반적으로 close() 메서드와 같은 외부 리소스를 해제하는 명시적인 방법도 제공합니다. 이러한 개체를 명시적으로 닫는 프로그램을 사용하는 것이 좋습니다. ‘try…finally’ 문과 ‘with’ 문은 이를 수행하는 편리한 방법을 제공합니다.

일부 객체는 다른 객체에 대한 참조를 포함합니다. 이를 컨테이너라고 합니다. 컨테이너의 예로는 튜플, 목록 및 사전이 있습니다. 참조는 컨테이너 값의 일부입니다. 대부분의 경우 컨테이너의 값에 대해 이야기할 때 포함된 개체의 ID가 아니라 값을 의미합니다. 그러나 컨테이너의 변경 가능성에 대해 이야기할 때는 직접 포함된 개체의 ID만 암시됩니다. 따라서 불변 컨테이너(예: 튜플)에 가변 객체에 대한 참조가 포함된 경우 해당 가변 객체가 변경되면 해당 값이 변경됩니다.

유형은 객체 동작의 거의 모든 측면에 영향을 미칩니다. 개체 ID의 중요성도 어떤 의미에서는 영향을 받습니다. 변경 불가능한 유형의 경우 새 값을 계산하는 작업은 실제로 동일한 유형과 값을 가진 기존 개체에 대한 참조를 반환할 수 있지만 변경 가능한 개체의 경우에는 이것이 허용되지 않습니다. 예를 들어, a = 1 이후; b = 1, a와 b는 구현에 따라 값이 1인 동일한 객체를 참조하거나 참조하지 않을 수 있지만 c = [] 이후; d = [], c 및 d는 새로 생성된 두 개의 서로 다른 고유한 빈 목록을 참조하도록 보장됩니다. (c = d = []는 c와 d 모두에 동일한 개체를 할당합니다.)

3.2. The standard type hierarchy

다음은 Python에 내장된 유형의 목록입니다. 확장 모듈(구현에 따라 C, Java 또는 기타 언어로 작성됨)은 추가 유형을 정의할 수 있습니다. 미래 버전의 Python은 유형 계층에 유형을 추가할 수 있습니다(예: 유리수, 효율적으로 저장된 정수 배열 등). 이러한 추가는 종종 대신 표준 라이브러리를 통해 제공됩니다.

아래 유형 설명 중 일부에는 ‘특수 속성’을 나열하는 단락이 포함되어 있습니다. 이러한 속성은 구현에 대한 액세스를 제공하며 일반적인 용도로 사용되지 않습니다. 그들의 정의는 미래에 바뀔 수 있습니다.

None

이 유형에는 단일 값이 있습니다. 이 값을 가진 단일 개체가 있습니다. 이 객체는 기본 제공 이름 None을 통해 액세스됩니다. 많은 상황에서 값이 없음을 나타내는 데 사용됩니다. 예를 들어 명시적으로 아무 것도 반환하지 않는 함수에서 반환됩니다. 진리값은 거짓입니다.

NotImplemented

이 유형에는 단일 값이 있습니다. 이 값을 가진 단일 개체가 있습니다. 이 개체는 기본 제공 이름 NotImplemented를 통해 액세스됩니다. 숫자 메서드 및 풍부한 비교 메서드는 제공된 피연산자에 대한 연산을 구현하지 않는 경우 이 값을 반환해야 합니다. (그런 다음 인터프리터는 연산자에 따라 반영된 작업 또는 다른 폴백을 시도합니다.) 부울 컨텍스트에서 평가하면 안 됩니다.

자세한 내용은 산술 연산 구현을 참조하세요.

버전 3.9에서 변경: 부울 컨텍스트에서 NotImplemented를 평가하는 것은 더 이상 사용되지 않습니다. 현재 true로 평가되는 동안 DeprecationWarning을 내보냅니다. 미래 버전의 Python에서는 TypeError가 발생합니다.

Ellipsis

이 유형에는 단일 값이 있습니다. 이 값을 가진 단일 개체가 있습니다. 이 개체는 리터럴 또는 기본 제공 이름 Ellipsis를 통해 액세스됩니다. 그것의 진리값은 참입니다.

numbers.Number

이들은 숫자 리터럴에 의해 생성되고 산술 연산자 및 산술 내장 함수에 의해 결과로 반환됩니다. 숫자 개체는 변경할 수 없습니다. 한번 생성되면 그 가치는 절대 변하지 않습니다. 파이썬 숫자는 물론 수학 숫자와 밀접한 관련이 있지만 컴퓨터의 숫자 표현에는 한계가 있습니다.

repr() 및 str()에 의해 계산되는 숫자 클래스의 문자열 표현에는 다음과 같은 속성이 있습니다.

  • 이들은 클래스 생성자에 전달될 때 원래 숫자 값을 갖는 객체를 생성하는 유효한 숫자 리터럴입니다.
  • 가능한 경우 10진법으로 표현됩니다.
  • 소수점 앞의 단일 0을 제외한 선행 0은 표시되지 않습니다.
  • 소수점 뒤의 단일 0을 제외한 후행 0은 표시되지 않습니다.
  • 숫자가 음수일 때만 부호가 표시됩니다.

Python은 정수, 부동 소수점 숫자 및 복소수를 구별합니다.

numbers.Integral

이들은 수학적 정수 집합(양수 및 음수)의 요소를 나타냅니다.

정수에는 두 가지 유형이 있습니다.

Integers (int)
이들은 사용 가능한 (가상) 메모리에만 적용되는 무제한 범위의 숫자를 나타냅니다. 시프트 및 마스크 연산의 목적을 위해 이진 표현이 가정되고 음수는 2의 보수 변형으로 표현되어 왼쪽으로 확장되는 무한 부호 비트 문자열의 환상을 제공합니다.

Booleans (bool)
이것들은 참값 False와 True를 나타냅니다. False 및 True 값을 나타내는 두 개체는 유일한 부울 개체입니다. 부울 유형은 정수 유형의 하위 유형이며 부울 값은 거의 모든 컨텍스트에서 각각 값 0과 1처럼 작동합니다. 예외는 문자열로 변환할 때 문자열 “False” 또는 “True”가 반환된다는 것입니다. , 각각.

정수 표현에 대한 규칙은 음의 정수와 관련된 시프트 및 마스크 연산을 가장 의미 있게 해석하기 위한 것입니다.

numbers.Real (float)


이들은 기계 수준 배정도 부동 소수점 숫자를 나타냅니다. 허용되는 범위와 오버플로 처리를 위해 기본 기계 아키텍처(및 C 또는 Java 구현)에 따라 결정됩니다. Python은 단정밀도 부동 소수점 숫자를 지원하지 않습니다. 일반적으로 이를 사용하는 이유인 프로세서 및 메모리 사용량 절감은 Python에서 개체를 사용하는 오버헤드로 인해 왜소해지기 때문에 두 종류의 부동 소수점 숫자로 언어를 복잡하게 만들 이유가 없습니다.

numbers.Complex (complex)


이것들은 복소수를 기계 수준 배정밀도 부동 소수점 숫자 쌍으로 나타냅니다. 부동 소수점 숫자와 동일한 주의 사항이 적용됩니다. 복소수 z의 실수부와 허수부는 읽기 전용 속성 z.realz.imag를 통해 검색할 수 있습니다.

Sequences

이들은 음수가 아닌 숫자로 인덱싱된 유한 순서 집합을 나타냅니다. 내장 함수 len()은 시퀀스의 항목 수를 반환합니다. 시퀀스의 길이가 n인 경우 인덱스 집합에는 숫자 0, 1, …, n-1이 포함됩니다. 시퀀스 a의 항목 i는 a[i]에 의해 선택됩니다.

시퀀스는 슬라이싱도 지원합니다. a[i:j]는 i <= k < j인 인덱스 k를 가진 모든 항목을 선택합니다. 표현식으로 사용될 때 슬라이스는 동일한 유형의 시퀀스입니다. 이는 인덱스 세트가 0부터 시작하도록 번호가 다시 지정됨을 의미합니다.

일부 시퀀스는 세 번째 “단계” 매개 변수를 사용하여 “확장된 슬라이싱”도 지원합니다. a[i:j:k]는 인덱스 x가 있는 a의 모든 항목을 선택합니다. 여기서 x = i + n*k, n >= 0 및 i <= x입니다. < j.

시퀀스는 가변성에 따라 구분됩니다.

Immutable sequences

불변 시퀀스 유형의 객체는 일단 생성되면 변경할 수 없습니다. (객체가 다른 객체에 대한 참조를 포함하는 경우 이러한 다른 객체는 변경 가능하고 변경될 수 있습니다. 그러나 변경 불가능한 객체가 직접 참조하는 객체 컬렉션은 변경할 수 없습니다.)

다음 유형은 변경할 수 없는 시퀀스입니다.

Strings
문자열은 유니코드 코드 포인트를 나타내는 일련의 값입니다. U+0000 – U+10FFFF 범위의 모든 코드 포인트는 문자열로 나타낼 수 있습니다. Python에는 char 유형이 없습니다. 대신 문자열의 모든 코드 포인트는 길이가 1인 문자열 객체로 표시됩니다. 내장 함수 ord()는 코드 포인트를 문자열 형식에서 0 – 10FFFF 범위의 정수로 변환합니다. chr()은 0 – 10FFFF 범위의 정수를 해당 길이 1 문자열 객체로 변환합니다. str.encode()는 주어진 텍스트 인코딩을 사용하여 str을 바이트로 변환하는 데 사용할 수 있으며 bytes.decode()는 그 반대를 달성하는 데 사용할 수 있습니다.

Tuples
튜플의 항목은 임의의 파이썬 객체입니다. 두 개 이상의 항목으로 구성된 튜플은 쉼표로 구분된 표현식 목록으로 구성됩니다. 한 항목의 튜플(‘싱글톤’)은 표현식에 쉼표를 추가하여 형성할 수 있습니다(표현식을 그룹화하는 데 괄호를 사용할 수 있어야 하므로 표현식 자체는 튜플을 생성하지 않습니다). 빈 튜플은 빈 괄호 쌍으로 구성될 수 있습니다.

Bytes
바이트 객체는 불변 배열입니다. 항목은 0 <= x < 256 범위의 정수로 표현되는 8비트 바이트입니다. b’abc’와 같은 바이트 리터럴과 내장 bytes() 생성자를 사용하여 바이트 객체를 생성할 수 있습니다. 또한 바이트 객체는 decode() 메서드를 통해 문자열로 디코딩될 수 있습니다.

Mutable sequences

변경 가능한 시퀀스는 생성된 후 변경할 수 있습니다. 구독 및 슬라이싱 표기법은 할당 및 del(삭제) 문의 대상으로 사용할 수 있습니다.

현재 다음과 같은 두 가지 고유 변경 가능 시퀀스 유형이 있습니다.

Lists
목록의 항목은 임의의 Python 객체입니다. 목록은 쉼표로 구분된 식 목록을 대괄호 안에 넣어 구성됩니다. (길이가 0 또는 1인 목록을 구성하는 데 필요한 특별한 경우가 없음에 유의하십시오.)

Byte Arrays
bytearray 객체는 변경 가능한 배열입니다. 내장 bytearray() 생성자에 의해 생성됩니다. 변경 가능(따라서 해시 불가능)한 것 외에도 바이트 배열은 변경 불가능한 바이트 객체와 동일한 인터페이스 및 기능을 제공합니다.

확장 모듈 배열은 collections 모듈과 마찬가지로 변경 가능한 시퀀스 유형의 추가 예를 제공합니다.

Set types

이들은 고유하고 변경 불가능한 객체의 정렬되지 않은 유한 집합을 나타냅니다. 따라서 아래 첨자로 인덱싱할 수 없습니다. 그러나 반복될 수 있으며 내장 함수 len()은 집합의 항목 수를 반환합니다. 세트의 일반적인 용도는 빠른 멤버십 테스트, 시퀀스에서 중복 제거, 교집합, 합집합, 차이 및 대칭 차이와 같은 수학적 연산 계산입니다.

집합 요소의 경우 사전 키와 동일한 불변성 규칙이 적용됩니다. 숫자 유형은 숫자 비교에 대한 일반적인 규칙을 따릅니다. 두 숫자가 같다고 비교되면(예: 1과 1.0) 둘 중 하나만 집합에 포함될 수 있습니다.

현재 두 가지 고유 세트 유형이 있습니다.

Sets
이들은 변경 가능한 집합을 나타냅니다. 이들은 내장 set() 생성자에 의해 생성되며 나중에 add()와 같은 여러 메서드로 수정할 수 있습니다.

Frozen sets
이들은 불변 세트를 나타냅니다. 이들은 내장 frozenset() 생성자에 의해 생성됩니다. frozenset은 변경 불가능하고 해시 가능하므로 다른 집합의 요소로 다시 사용하거나 사전 키로 사용할 수 있습니다.

Mappings

이들은 임의의 인덱스 세트로 인덱싱된 유한 객체 세트를 나타냅니다. 아래 첨자 표기법 a[k]는 매핑 a에서 k로 인덱싱된 항목을 선택합니다. 이것은 식에서 할당 또는 del 문의 대상으로 사용할 수 있습니다. 내장 함수 len()은 매핑의 항목 수를 반환합니다.

현재 단일 고유 매핑 유형이 있습니다.

Dictionaries

이들은 거의 임의의 값으로 인덱싱된 유한 개체 집합을 나타냅니다. 키로 허용되지 않는 유일한 유형의 값은 목록이나 사전 또는 객체 ID가 아닌 값으로 비교되는 기타 변경 가능한 유형을 포함하는 값입니다. 그 이유는 사전을 효율적으로 구현하려면 키의 해시 값이 일정하게 유지되어야 하기 때문입니다. 키에 사용되는 숫자 유형은 숫자 비교에 대한 일반 규칙을 따릅니다. 두 숫자가 같다고 비교되면(예: 1과 1.0) 동일한 사전 항목을 색인화하는 데 서로 교환하여 사용할 수 있습니다.

사전은 삽입 순서를 유지합니다. 즉, 사전에 순차적으로 추가된 순서대로 키가 생성됩니다. 기존 키를 교체해도 순서는 변경되지 않지만 키를 제거하고 다시 삽입하면 이전 위치를 유지하는 대신 끝에 추가됩니다.

사전은 변경 가능합니다. {…} 표기법으로 만들 수 있습니다(사전 표시 섹션 참조).

확장 모듈 dbm.ndbm 및 dbm.gnu는 컬렉션 모듈과 마찬가지로 매핑 유형의 추가 예를 제공합니다.

버전 3.7에서 변경: 사전은 Python 3.6 이전 버전에서 삽입 순서를 유지하지 않았습니다. CPython 3.6에서는 삽입 순서가 유지되었지만 당시에는 언어 보장이 아니라 구현 세부 사항으로 간주되었습니다.

Callable types

다음은 함수 호출 작업(호출 섹션 참조)이 적용될 수 있는 유형입니다.

User-defined functions

사용자 정의 함수 개체는 함수 정의에 의해 생성됩니다(함수 정의 섹션 참조). 함수의 형식 매개변수 목록과 동일한 수의 항목을 포함하는 인수 목록으로 호출해야 합니다.

Special attributes:

AttributeMeaning
__doc__함수의 문서 문자열 또는 사용할 수 없는 경우 None; 하위 클래스에 의해 상속되지 않습니다.Writable
__name__함수의 이름입니다.Writable
__qualname__함수의 정규화된 이름입니다.
버전 3.3의 새로운 기능.
Writable
__module__함수가 정의된 모듈의 이름 또는 사용할 수 없는 경우 None.Writable
__defaults__기본값이 있는 인수에 대한 기본 인수 값을 포함하는 튜플 또는 기본값이 있는 인수가 없으면 None입니다.Writable
__code__컴파일된 함수 본문을 나타내는 코드 개체입니다.Writable
__globals__함수의 전역 변수를 포함하는 사전에 대한 참조 — 함수가 정의된 모듈의 전역 네임스페이스.Read-only
__dict__임의의 함수 속성을 지원하는 네임스페이스.Writable
__closure__없음 또는 함수의 자유 변수에 대한 바인딩을 포함하는 셀 튜플. cell_contents 속성에 대한 정보는 아래를 참조하십시오.Read-only
__annotations__매개변수의 주석을 포함하는 dict입니다. dict의 키는 매개변수 이름과 반환 주석(제공된 경우)의 ‘return’입니다. 이 속성 작업에 대한 자세한 내용은 주석 모범 사례를 참조하십시오.Writable
__kwdefaults__키워드 전용 매개변수의 기본값을 포함하는 사전입니다.Writable

“Writable”로 표시된 대부분의 속성은 할당된 값의 유형을 확인합니다.

함수 객체는 예를 들어 메타데이터를 함수에 첨부하는 데 사용할 수 있는 임의의 속성 가져오기 및 설정도 지원합니다. 일반 속성 점 표기법은 이러한 속성을 가져오고 설정하는 데 사용됩니다. 현재 구현은 사용자 정의 함수의 함수 속성만 지원합니다. 내장 함수의 함수 속성은 향후 지원될 수 있습니다.

셀 개체에는 cell_contents 속성이 있습니다. 셀 값을 가져오고 값을 설정하는 데 사용할 수 있습니다.

함수 정의에 대한 추가 정보는 해당 코드 개체에서 검색할 수 있습니다. 아래의 내부 유형에 대한 설명을 참조하십시오. 셀 유형은 types 모듈에서 액세스할 수 있습니다.

Instance methods

인스턴스 메서드 개체는 클래스, 클래스 인스턴스 및 호출 가능한 개체(일반적으로 사용자 정의 함수)를 결합합니다.

특수 읽기 전용 속성: __self__는 클래스 인스턴스 객체이고 __func__은 함수 객체입니다. __doc__은 메서드의 문서입니다(__func__.__doc__과 동일). __name__은 메서드 이름입니다(__func__.__name__과 동일). __module__은 메서드가 정의된 모듈의 이름이거나 사용할 수 없는 경우 None입니다.

메서드는 기본 함수 개체의 임의 함수 특성에 대한 액세스(설정은 아님)도 지원합니다.

해당 속성이 사용자 정의 함수 개체 또는 클래스 메서드 개체인 경우 클래스의 속성을 가져올 때(아마도 해당 클래스의 인스턴스를 통해) 사용자 정의 메서드 개체가 생성될 수 있습니다.

인스턴스 중 하나를 통해 클래스에서 사용자 정의 함수 개체를 검색하여 인스턴스 메서드 개체를 만들 때 해당 __self__ 특성이 인스턴스이고 메서드 개체가 바인딩되었다고 합니다. 새 메소드의 __func__ 속성은 원래 함수 객체입니다.

클래스 또는 인스턴스에서 클래스 메서드 객체를 검색하여 인스턴스 메서드 객체를 만들 때 __self__ 속성은 클래스 자체이고 __func__ 속성은 클래스 메서드의 기반이 되는 함수 객체입니다.

인스턴스 메소드 객체가 호출되면 기본 함수(__func__)가 호출되어 인수 목록 앞에 클래스 인스턴스(__self__)를 삽입합니다. 예를 들어, C가 함수 f()에 대한 정의를 포함하는 클래스이고 x가 C의 인스턴스일 때 x.f(1)을 호출하는 것은 C.f(x, 1)을 호출하는 것과 같습니다.

인스턴스 메서드 객체가 클래스 메서드 객체에서 파생되면 __self__에 저장된 “클래스 인스턴스”는 실제로 클래스 자체가 되므로 x.f(1) 또는 C.f(1)를 호출하는 것은 f(C,1)을 호출하는 것과 같습니다. ) 여기서 f는 기본 함수입니다.

함수 개체에서 인스턴스 메서드 개체로의 변환은 속성이 인스턴스에서 검색될 때마다 발생합니다. 경우에 따라 유익한 최적화는 특성을 지역 변수에 할당하고 해당 지역 변수를 호출하는 것입니다. 또한 이 변환은 사용자 정의 함수에 대해서만 발생합니다. 다른 호출 가능한 객체(및 모든 호출 불가능한 객체)는 변환 없이 검색됩니다. 클래스 인스턴스의 특성인 사용자 정의 함수는 바인딩된 메서드로 변환되지 않는다는 점도 중요합니다. 이것은 함수가 클래스의 속성일 때만 발생합니다.

Generator functions

yield 문을 사용하는 함수나 메서드(yield 문 참조)를 제너레이터 함수라고 합니다. 이러한 함수는 호출될 때 항상 함수 본문을 실행하는 데 사용할 수 있는 반복자 객체를 반환합니다. 반복자의 iterator.__next__() 메서드를 호출하면 yield 문을 사용하여 값을 제공할 때까지 함수가 실행됩니다. 함수가 return 문을 실행하거나 끝에서 떨어지면 StopIteration 예외가 발생하고 반복자는 반환할 값 집합의 끝에 도달합니다.

Coroutine functions

async def를 사용하여 정의된 함수 또는 메서드를 코루틴 함수라고 합니다. 이러한 함수는 호출될 때 코루틴 객체를 반환합니다. 여기에는 async with 및 async for 문뿐만 아니라 await 표현식이 포함될 수 있습니다. 코루틴 객체 섹션도 참조하십시오.

Asynchronous generator functions

async def를 사용하여 정의되고 yield 문을 사용하는 함수 또는 메서드를 비동기 생성기 함수라고 합니다. 이러한 함수는 호출될 때 함수 본문을 실행하기 위해 async for 문에서 사용할 수 있는 비동기 이터레이터 객체를 반환합니다.

비동기 이터레이터의 aiterator.__anext__ 메서드를 호출하면 awaitable이 반환될 것입니다. awaitable은 yield 표현식을 사용하여 값을 제공할 때까지 실행됩니다. 함수가 빈 반환 문을 실행하거나 끝에서 떨어지면 StopAsyncIteration 예외가 발생하고 비동기 반복자는 산출할 값 집합의 끝에 도달하게 됩니다.

Built-in functions

내장 함수 개체는 C 함수를 둘러싼 래퍼입니다. 내장 함수의 예는 len() 및 math.sin()입니다(math는 표준 내장 모듈입니다). 인수의 수와 유형은 C 함수에 의해 결정됩니다. 특수 읽기 전용 속성: __doc__은 함수의 문서 문자열이거나 사용할 수 없는 경우 None입니다. __name__은 함수의 이름입니다. __self__는 None으로 설정됩니다(하지만 다음 항목 참조). __module__은 함수가 정의된 모듈의 이름이거나 사용할 수 없는 경우 None입니다.

Built-in methods

이것은 실제로 내장 함수의 다른 변장이며, 이번에는 암시적 추가 인수로 C 함수에 전달된 개체를 포함합니다. 내장 메서드의 예는 alist가 목록 객체라고 가정할 때 alist.append()입니다. 이 경우 특수한 읽기 전용 속성 __self__는 alist로 표시된 객체로 설정됩니다.

Classes

클래스는 호출 가능합니다. 이러한 객체는 일반적으로 자신의 새 인스턴스에 대한 팩토리 역할을 하지만 __new__()를 재정의하는 클래스 유형에 대한 변형이 가능합니다. 호출의 인수는 __new__()에 전달되고, 일반적인 경우에는 __init__()에 전달되어 새 인스턴스를 초기화합니다.

Class Instances

임의 클래스의 인스턴스는 해당 클래스에 __call__() 메서드를 정의하여 호출 가능하게 만들 수 있습니다.

Modules

모듈은 Python 코드의 기본 구성 단위이며 import 문에 의해 호출되거나 importlib.import_module() 및 내장 __import()__와 같은 함수를 호출하여 가져오기 시스템에 의해 생성됩니다. 모듈 객체에는 사전 객체(모듈에 정의된 함수의__globals__ 속성이 참조하는 사전)에 의해 구현된 네임스페이스가 있습니다. 속성 참조는 이 사전의 조회로 변환됩니다. 예를 들어 m.x는 m.__dict__["x"]와 같습니다. 모듈 객체는 모듈을 초기화하는 데 사용되는 코드 객체를 포함하지 않습니다(초기화가 완료되면 필요하지 않기 때문).

속성 할당은 모듈의 네임스페이스 사전을 업데이트합니다. 예를 들어 m.x = 1은 m.__dict__["x"] = 1과 같습니다.

미리 정의된(쓰기 가능) 속성:

__name__
모듈의 이름입니다.

__doc__
모듈의 문서 문자열 또는 사용할 수 없는 경우 None입니다.

__file__
모듈이 파일에서 로드된 경우 모듈이 로드된 파일의 경로 이름입니다. __file__ 속성은 인터프리터에 정적으로 연결된 C 모듈과 같은 특정 유형의 모듈에 대해 누락될 수 있습니다. 공유 라이브러리에서 동적으로 로드된 확장 모듈의 경우 공유 라이브러리 파일의 경로 이름입니다.

__annotations__
모듈 본문 실행 중에 수집된 변수 주석을 포함하는 사전입니다. __annotations__ 작업에 대한 모범 사례는 Annotations Best Practices를 참조하십시오.

특수 읽기 전용 속성: __dict__는 사전 객체로서의 모듈의 네임스페이스입니다.

CPython 구현 세부 사항: CPython이 모듈 사전을 지우는 방식으로 인해 사전에 여전히 활성 참조가 있더라도 모듈이 범위를 벗어나면 모듈 사전이 지워집니다. 이를 방지하려면 사전을 복사하거나 사전을 직접 사용하는 동안 모듈을 유지하십시오.

Custom classes

사용자 지정 클래스 유형은 일반적으로 클래스 정의에 의해 생성됩니다(클래스 정의 섹션 참조). 클래스에는 사전 개체에 의해 구현된 네임스페이스가 있습니다. 클래스 속성 참조는 이 사전에서 검색으로 변환됩니다. 예를 들어 C.xC.__dict__["x"]로 변환됩니다(속성을 찾는 다른 방법을 허용하는 많은 후크가 있지만). 속성 이름이 없으면 기본 클래스에서 속성 검색이 계속됩니다. 이 기본 클래스 검색은 공통 조상으로 돌아가는 여러 상속 경로가 있는 ‘다이아몬드’ 상속 구조가 있는 경우에도 올바르게 작동하는 C3 메서드 해결 순서를 사용합니다. Python에서 사용하는 C3 MRO에 대한 추가 세부 정보는 https://www.python.org/download/releases/2.3/mro/에서 2.3 릴리스와 함께 제공되는 설명서에서 찾을 수 있습니다.

클래스 속성 참조(예를 들어 클래스 C에 대한)가 클래스 메소드 객체를 산출할 때 __self __속성이 C인 인스턴스 메소드 객체로 변환됩니다. 정적 메소드 객체를 산출할 때 다음으로 래핑된 객체로 변환됩니다. 정적 메소드 객체. 클래스에서 검색된 속성이 __dict__에 실제로 포함된 속성과 다를 수 있는 또 다른 방법에 대해서는 설명자 구현 섹션을 참조하세요.

클래스 특성 할당은 기본 클래스의 사전이 아니라 클래스의 사전을 업데이트합니다.

클래스 객체를 호출(위 참조)하여 클래스 인스턴스(아래 참조)를 생성할 수 있습니다.

Special attributes:

__name__
클래스 이름입니다.

__module__
클래스가 정의된 모듈의 이름입니다.

__dict__
클래스의 네임스페이스를 포함하는 사전입니다.

__bases__
기본 클래스 목록에 나타나는 순서대로 기본 클래스를 포함하는 튜플입니다.

__doc__
클래스의 문서 문자열 또는 정의되지 않은 경우 None입니다.

__annotations__
클래스 본문 실행 중에 수집된 변수 주석을 포함하는 사전입니다. __annotations__ 작업에 대한 모범 사례는 Annotations Best Practices를 참조하십시오.

Class instances

클래스 인스턴스는 클래스 개체를 호출하여 생성됩니다(위 참조). 클래스 인스턴스에는 속성 참조가 검색되는 첫 번째 위치인 사전으로 구현된 네임스페이스가 있습니다. 거기에서 속성을 찾을 수 없고 인스턴스의 클래스에 해당 이름의 속성이 있는 경우 클래스 속성으로 검색이 계속됩니다. 사용자 정의 함수 개체인 클래스 속성이 발견되면 __self__ 속성이 인스턴스인 인스턴스 메서드 개체로 변환됩니다. 정적 메서드 및 클래스 메서드 개체도 변환됩니다. 위의 “클래스”를 참조하십시오. 인스턴스를 통해 검색된 클래스의 속성이 클래스의 __dict__에 실제로 저장된 객체와 다를 수 있는 또 다른 방법에 대해서는 설명자 구현 섹션을 참조하세요. 클래스 속성이 발견되지 않고 객체의 클래스에 __getattr__() 메서드가 있으면 조회를 충족하기 위해 호출됩니다.

속성 할당 및 삭제는 클래스의 사전이 아닌 인스턴스의 사전을 업데이트합니다. 클래스에 __setattr__() 또는 __delattr__() 메서드가 있으면 인스턴스 사전을 직접 업데이트하는 대신 이 메서드가 호출됩니다.

클래스 인스턴스는 특정 특수 이름을 가진 메서드가 있는 경우 숫자, 시퀀스 또는 매핑인 것처럼 가장할 수 있습니다. 특수 메소드 이름 섹션을 참조하십시오.

Special attributes: __dict__는 속성 사전입니다. __class__는 인스턴스의 클래스입니다.

I/O objects (also known as file objects)

파일 객체는 열린 파일을 나타냅니다. open() 내장 함수, os.popen(), os.fdopen(), 소켓 객체의 makefile() 메서드(및 제공되는 다른 함수나 메서드)와 같은 다양한 단축키를 사용하여 파일 개체를 만들 수 있습니다. 확장 모듈에 의해).

sys.stdin, sys.stdout 및 sys.stderr 개체는 인터프리터의 표준 입력, 출력 및 오류 스트림에 해당하는 파일 개체로 초기화됩니다. 그들은 모두 텍스트 모드에서 열려 있으므로 io.TextIOBase 추상 클래스에 의해 정의된 인터페이스를 따릅니다.

Internal types

인터프리터가 내부적으로 사용하는 몇 가지 유형이 사용자에게 노출됩니다. 해당 정의는 향후 버전의 인터프리터에서 변경될 수 있지만 여기에서는 완전성을 위해 언급합니다.

Code objects

코드 개체는 바이트 컴파일된 실행 가능한 Python 코드 또는 바이트코드를 나타냅니다. 코드 개체와 함수 개체의 차이점은 함수 개체에는 함수의 전역(함수가 정의된 모듈)에 대한 명시적 참조가 포함되는 반면 코드 개체에는 컨텍스트가 없다는 점입니다. 또한 기본 인수 값은 코드 개체가 아닌 함수 개체에 저장됩니다(런타임에 계산된 값을 나타내기 때문). 함수 개체와 달리 코드 개체는 변경할 수 없으며 변경 가능한 개체에 대한 참조(직접 또는 간접적)를 포함하지 않습니다.

특수 읽기 전용 속성: co_name은 함수 이름을 제공합니다. co_qualname은 정규화된 함수 이름을 제공합니다. co_argcount는 위치 인수의 총 수입니다(위치 전용 인수 및 기본값이 있는 인수 포함). co_posonlyargcount는 위치 전용 인수(기본값이 있는 인수 포함)의 수입니다. co_kwonlyargcount는 키워드 전용 인수(기본값이 있는 인수 포함)의 수입니다. co_nlocals는 함수가 사용하는 지역 변수(인수 포함)의 수입니다. co_varnames는 지역 변수의 이름을 포함하는 튜플입니다(인수 이름으로 시작). co_cellvars는 중첩 함수가 참조하는 지역 변수의 이름을 포함하는 튜플입니다. co_freevars는 자유 변수의 이름을 포함하는 튜플입니다. co_code는 바이트코드 명령의 시퀀스를 나타내는 문자열입니다. co_consts는 바이트코드에서 사용하는 리터럴을 포함하는 튜플입니다. co_names는 바이트코드에서 사용하는 이름을 포함하는 튜플입니다. co_filename은 코드가 컴파일된 파일 이름입니다. co_firstlineno는 함수의 첫 번째 줄 번호입니다. co_lnotab은 바이트코드 오프셋에서 줄 번호로의 매핑을 인코딩하는 문자열입니다(자세한 내용은 인터프리터의 소스 코드 참조). co_stacksize는 필요한 스택 크기입니다. co_flags는 인터프리터에 대한 여러 플래그를 인코딩하는 정수입니다.

다음 플래그 비트는 co_flags에 대해 정의됩니다. 함수가 *arguments 구문을 사용하여 위치 인수의 임의 개수를 허용하는 경우 비트 0x04가 설정됩니다. 함수가 **키워드 구문을 사용하여 임의의 키워드 인수를 허용하는 경우 비트 0x08이 설정됩니다. 함수가 생성기이면 비트 0x20이 설정됩니다.

Future 기능 선언(from __future__ import division)도 co_flags의 비트를 사용하여 특정 기능이 활성화된 상태로 코드 객체가 컴파일되었는지 여부를 나타냅니다. 비트 0x10 및 0x1000은 이전 버전의 Python에서 사용되었습니다.

co_flags의 다른 비트는 내부용으로 예약되어 있습니다.

코드 개체가 함수를 나타내는 경우 co_consts의 첫 번째 항목은 함수의 문서화 문자열이거나 정의되지 않은 경우 None입니다.

codeobject.co_positions()

코드 객체에서 각 바이트 코드 명령의 소스 코드 위치에 대한 반복 가능 항목을 반환합니다.

반복자는 (start_line, end_line, start_column, end_column)을 포함하는 튜플을 반환합니다. i번째 튜플은 i번째 명령으로 컴파일된 소스 코드의 위치에 해당합니다. 열 정보는 주어진 소스 라인에서 0-인덱스 utf-8 바이트 오프셋입니다.

이 위치 정보가 누락되었을 수 있습니다. 이러한 상황이 발생할 수 있는 일부 사례 목록:

  • -X no_debug_ranges로 인터프리터를 실행합니다.
  • -X no_debug_ranges를 사용하는 동안 컴파일된 pyc 파일을 로드합니다.
  • 인공 명령에 해당하는 튜플을 배치합니다.
  • 구현 특정 제한으로 인해 표시할 수 없는 줄 및 열 번호입니다.

이 경우 튜플 요소의 일부 또는 전부가 None일 수 있습니다.

버전 3.11의 새로운 기능.

참고 이 기능을 사용하려면 코드 개체에 열 위치를 저장해야 하므로 컴파일된 Python 파일의 디스크 사용량이나 인터프리터 메모리 사용량이 약간 증가할 수 있습니다. 추가 정보 저장을 피하거나 추가 추적 정보 인쇄를 비활성화하려면 -X no_debug_ranges 명령줄 플래그 또는 PYTHONNODEBUGRANGES 환경 변수를 사용할 수 있습니다.

Frame objects

프레임 개체는 실행 프레임을 나타냅니다. 트레이스백 객체(아래 참조)에서 발생할 수 있으며 등록된 트레이스 함수에도 전달됩니다.

특수 읽기 전용 속성: f_back은 이전 스택 프레임(호출자 쪽) 또는 이것이 맨 아래 스택 프레임인 경우 None입니다. f_code는 이 프레임에서 실행되는 코드 개체입니다. f_locals는 지역 변수를 찾는 데 사용되는 사전입니다. f_globals는 전역 변수에 사용됩니다. f_builtins는 내장(내재) 이름에 사용됩니다. f_lasti는 정확한 명령을 제공합니다(이것은 코드 객체의 바이트코드 문자열에 대한 인덱스입니다).

f_code에 액세스하면 obj 및 “f_code” 인수를 사용하여 감사 이벤트 object.__getattr__이 발생합니다.

쓰기 가능한 특수 속성: f_trace(None이 아닌 경우)는 코드 실행 중 다양한 이벤트에 대해 호출되는 함수입니다(디버거에서 사용됨). 일반적으로 각각의 새 소스 라인에 대해 이벤트가 트리거됩니다. 이는 f_trace_lines를 False로 설정하여 비활성화할 수 있습니다.

구현 시 f_trace_opcodes를 True로 설정하여 opcode별 이벤트를 요청할 수 있습니다. 추적 함수에 의해 발생한 예외가 추적 중인 함수로 탈출하는 경우 이로 인해 정의되지 않은 인터프리터 동작이 발생할 수 있습니다.

f_lineno는 프레임의 현재 줄 번호입니다. 추적 함수 내에서 이것에 쓰면 주어진 줄로 이동합니다(맨 아래 프레임에만 해당). 디버거는 f_lineno에 기록하여 점프 명령(일명 Set Next Statement)을 구현할 수 있습니다.

프레임 개체는 한 가지 방법을 지원합니다.

frame.clear()
이 메서드는 프레임이 보유한 지역 변수에 대한 모든 참조를 지웁니다. 또한 프레임이 제너레이터에 속한 경우 제너레이터가 종료됩니다. 이는 프레임 객체와 관련된 참조 순환을 중단하는 데 도움이 됩니다(예: 예외를 포착하고 나중에 사용하기 위해 트레이스백을 저장하는 경우).

프레임이 현재 실행 중인 경우 RuntimeError가 발생합니다.

버전 3.4의 새로운 기능.

Traceback objects

역추적 객체는 예외의 스택 추적을 나타냅니다. 트레이스백 객체는 예외가 발생할 때 암시적으로 생성되며 types.TracebackType을 호출하여 명시적으로 생성될 수도 있습니다.

암시적으로 생성된 트레이스백의 경우, 예외 핸들러 검색이 실행 스택을 풀 때, 풀린 각 레벨에서 트레이스백 객체가 현재 트레이스백 앞에 삽입됩니다. 예외 핸들러가 입력되면 프로그램에서 스택 추적을 사용할 수 있습니다. (try 문 섹션을 참조하십시오.) sys.exc_info()에 의해 반환된 튜플의 세 번째 항목 및 잡힌 예외의 __traceback__ 속성으로 액세스할 수 있습니다.

프로그램에 적합한 핸들러가 없으면 스택 추적이 표준 오류 스트림에 기록됩니다(적절하게 형식화됨). 인터프리터가 대화형이면 사용자가 sys.last_traceback으로 사용할 수도 있습니다.

명시적으로 생성된 트레이스백의 경우, 전체 스택 트레이스를 형성하기 위해 tb_next 속성을 연결하는 방법을 결정하는 것은 트레이스백 생성자에게 달려 있습니다.

특수 읽기 전용 속성: tb_frame은 현재 레벨의 실행 프레임을 가리킵니다. tb_lineno는 예외가 발생한 줄 번호를 제공합니다. tb_lasti는 정확한 명령을 나타냅니다. 일치하는 except 절이 없거나 finally 절이 있는 try 문에서 예외가 발생한 경우 트레이스백의 줄 번호와 마지막 명령어는 프레임 객체의 줄 번호와 다를 수 있습니다.

tb_frame에 액세스하면 obj 및 “tb_frame” 인수를 사용하여 감사 이벤트 object.__getattr__이 발생합니다.

쓰기 가능한 특수 속성: tb_next는 스택 추적의 다음 레벨(예외가 발생한 프레임 방향)이거나 다음 레벨이 없으면 None입니다.

버전 3.7에서 변경: 이제 트레이스백 객체를 파이썬 코드에서 명시적으로 인스턴스화할 수 있으며 기존 인스턴스의 tb_next 어트리뷰트를 업데이트할 수 있습니다.

Slice objects

슬라이스 객체는 __getitem__()메서드에 대한 슬라이스를 나타내는 데 사용됩니다. 또한 내장된 slice() 함수에 의해 생성됩니다.

특수 읽기 전용 속성: start는 하한값입니다. 중지는 상한입니다. 단계는 단계 값입니다. 생략하면 각각 None입니다. 이러한 속성은 모든 유형을 가질 수 있습니다.

슬라이스 개체는 하나의 메서드를 지원합니다:

slice.indices(selflength)
이 메서드는 단일 정수 인수 길이를 사용하고 슬라이스 개체가 길이 항목 시퀀스에 적용될 경우 설명하는 슬라이스에 대한 정보를 계산합니다. 세 개의 정수로 구성된 튜플을 반환합니다. 각각 시작 및 중지 인덱스와 슬라이스의 단계 또는 보폭입니다. 누락되거나 범위를 벗어난 인덱스는 일반 슬라이스와 일치하는 방식으로 처리됩니다.

Static method objects

정적 메소드 객체는 함수 객체가 위에서 설명한 메소드 객체로 변환되지 않도록 하는 방법을 제공합니다. 정적 메서드 개체는 일반적으로 사용자 정의 메서드 개체인 다른 개체를 감싸는 래퍼입니다. 클래스 또는 클래스 인스턴스에서 정적 메서드 개체를 검색할 때 실제로 반환되는 개체는 더 이상 변환되지 않는 래핑된 개체입니다. 정적 메소드 객체도 호출 가능합니다. 정적 메소드 객체는 내장 staticmethod() 생성자에 의해 생성됩니다.

Class method objects

클래스 메서드 개체는 정적 메서드 개체와 마찬가지로 클래스 및 클래스 인스턴스에서 해당 개체를 검색하는 방식을 변경하는 다른 개체 주위의 래퍼입니다. 이러한 검색 시 클래스 메서드 개체의 동작은 위의 “사용자 정의 메서드”에 설명되어 있습니다. 클래스 메소드 객체는 내장 classmethod() 생성자에 의해 생성됩니다.

3.3. Special method names

클래스는 특수 이름을 가진 메서드를 정의하여 특수 구문(예: 산술 연산 또는 첨자 및 슬라이싱)에 의해 호출되는 특정 연산을 구현할 수 있습니다. 이것은 연산자 오버로딩에 대한 Python의 접근 방식으로, 클래스가 언어 연산자와 관련하여 자체 동작을 정의할 수 있도록 합니다. 예를 들어, 클래스가 __getitem__()이라는 메서드를 정의하고 x가 이 클래스의 인스턴스인 경우 x[i]는 대략 type(x).__getitem__(x, i)와 동일합니다. 언급된 경우를 제외하고 작업 실행 시도는 적절한 메서드가 정의되지 않은 경우(일반적으로 AttributeError 또는 TypeError) 예외를 발생시킵니다.

특수 메서드를 없음으로 설정하면 해당 작업을 사용할 수 없음을 나타냅니다. 예를 들어, 클래스가 __iter__()None으로 설정하면 클래스는 반복할 수 없으므로 인스턴스에서 iter()를 호출하면 TypeError가 발생합니다(__getitem__()으로 돌아가지 않음).

내장 유형을 에뮬레이트하는 클래스를 구현할 때 에뮬레이션은 모델링되는 개체에 적합한 정도로만 구현하는 것이 중요합니다. 예를 들어, 일부 시퀀스는 개별 요소 검색과 잘 작동할 수 있지만 슬라이스 추출은 의미가 없을 수 있습니다. (이에 대한 한 가지 예는 W3C의 문서 개체 모델의 NodeList 인터페이스입니다.)

3.3.1. Basic customization

object.__new__(cls[, …])

클래스의 새 인스턴스를 만들기 위해 호출됩니다. __new__() 는 인스턴스가 요청된 클래스를 첫 번째 인수로 취하는 정적 메서드(특별한 경우이므로 그렇게 선언할 필요가 없음)입니다. 나머지 인수는 개체 생성자 식(클래스 호출)에 전달된 인수입니다. __new__()의 반환 값은 새 객체 인스턴스(일반적으로 cls의 인스턴스)여야 합니다.

일반적인 구현은 적절한 인수와 함께 super().__new__(cls[, …]) 를 사용하여 슈퍼클래스의 __new__()메서드를 호출한 다음 새로 생성된 인스턴스를 반환하기 전에 필요에 따라 수정하여 클래스의 새 인스턴스를 만듭니다.

객체 생성 중에 __new__()가 호출되고 cls의 인스턴스를 반환하면 새 인스턴스의 __init__() 메서드는 __init__(self[, …])처럼 호출됩니다. 여기서 self는 새 인스턴스이고 나머지 인수는 개체 생성자에 전달된 것과 동일합니다.

__new__()가 cls의 인스턴스를 반환하지 않으면 새 인스턴스의__init__() 메서드가 호출되지 않습니다.

__new__()는 주로 불변 유형(int, str 또는 튜플과 같은)의 하위 클래스가 인스턴스 생성을 사용자 정의할 수 있도록 하기 위한 것입니다. 또한 일반적으로 클래스 생성을 사용자 지정하기 위해 사용자 지정 메타클래스에서 재정의됩니다.

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에 대한 참조 카운트를 1씩 감소시키고 후자는 x의 참조 카운트가 0에 도달할 때만 호출됩니다.

CPython 구현 세부 사항: 참조 순환이 개체의 참조 횟수가 0이 되는 것을 방지할 수 있습니다. 이 경우 주기는 나중에 주기적 가비지 수집기에 의해 감지되고 삭제됩니다. 참조 순환의 일반적인 원인은 지역 변수에서 예외가 발생한 경우입니다. 그런 다음 프레임의 로컬은 트레이스백에서 포착된 모든 프레임의 로컬을 참조하는 자체 트레이스백을 참조하는 예외를 참조합니다.

gc 모듈에 대한 설명서도 참조하십시오.

Warning: __del__() 메서드가 호출되는 불안정한 상황으로 인해 실행 중에 발생하는 예외는 무시되고 대신 sys.stderr에 경고가 인쇄됩니다. 특히:
• __del__()은 임의의 스레드를 포함하여 임의의 코드가 실행될 때 호출될 수 있습니다. __del__()이 잠금을 취하거나 다른 차단 리소스를 호출해야 하는 경우 __del__()을 실행하기 위해 중단된 코드가 리소스를 이미 차지했을 수 있으므로 교착 상태가 될 수 있습니다.
• __del__()은 인터프리터 종료 중에 실행될 수 있습니다. 결과적으로 액세스해야 하는 전역 변수(다른 모듈 포함)가 이미 삭제되었거나 없음으로 설정되었을 수 있습니다. Python은 이름이 단일 밑줄로 시작하는 전역이 다른 전역이 삭제되기 전에 모듈에서 삭제되도록 보장합니다. 그러한 전역에 대한 다른 참조가 존재하지 않는 경우, 이것은 가져온 모듈이 __del__() 메서드가 호출될 때 여전히 사용 가능한지 확인하는 데 도움이 될 수 있습니다.

object.__repr__(self)

객체의 “공식적인” 문자열 표현을 계산하기 위해 repr() 내장 함수에 의해 호출됩니다. 가능하다면 이것은 동일한 값을 가진 객체를 재생성하는 데 사용할 수 있는 유효한 Python 표현식처럼 보여야 합니다(적절한 환경이 제공됨). 이것이 가능하지 않으면 <…일부 유용한 설명…> 형식의 문자열이 반환되어야 합니다. 반환 값은 문자열 개체여야 합니다. 클래스가 __repr__()을 정의하지만 __str__()을 정의하지 않는 경우 해당 클래스 인스턴스의 “비공식” 문자열 표현이 필요할 때도 __repr__()이 사용됩니다.

이것은 일반적으로 디버깅에 사용되므로 표현이 정보가 풍부하고 모호하지 않은 것이 중요합니다.

object.__str__(self)

str(객체)와 내장 함수 format() 및 print()에 의해 호출되어 객체의 “비공식” 또는 멋지게 인쇄 가능한 문자열 표현을 계산합니다. 반환 값은 문자열 개체여야 합니다.

이 메서드는 __str__()이 유효한 파이썬 표현식을 반환할 것이라는 기대가 없다는 점에서 object.__repr__()과 다릅니다: 더 편리하거나 간결한 표현을 사용할 수 있습니다.

내장 유형 객체에 의해 정의된 기본 구현은 object.__repr__()을 호출합니다.

object.__bytes__(self)

객체의 바이트 문자열 표현을 계산하기 위해 바이트에 의해 호출됩니다. 바이트 객체를 반환해야 합니다.

object.__format__(selfformat_spec)

format() 내장 함수에 의해 호출되고, 확장에 의해 형식이 지정된 문자열 리터럴과 str.format() 메서드의 평가가 객체의 “포맷된” 문자열 표현을 생성합니다. format_spec 인수는 원하는 형식 지정 옵션에 대한 설명이 포함된 문자열입니다. format_spec 인수의 해석은 __format__()을 구현하는 유형에 따라 다르지만 대부분의 클래스는 내장 유형 중 하나에 형식 지정을 위임하거나 유사한 형식 지정 옵션 구문을 사용합니다.

표준 형식 구문에 대한 설명은 형식 사양 미니 언어를 참조하십시오.

반환 값은 문자열 개체여야 합니다.

버전 3.4에서 변경: 객체 자체의 __format__ 메서드는 비어 있지 않은 문자열이 전달되면 TypeError 를 발생시킵니다.

버전 3.7에서 변경: object.__format__(x, ”)는 이제 format(str(x), ”)이 아니라 str(x)와 동일합니다.

object.__lt__(selfother)
object.__le__(selfother)
object.__eq__(selfother)
object.__ne__(selfother)
object.__gt__(selfother)
object.__ge__(selfother)

소위 “풍부한 비교” 방법입니다. 연산자 기호와 메서드 이름 간의 대응은 다음과 같습니다. 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()을 호출하여 결과가 참인지 거짓인지 결정합니다. .

기본적으로 객체는 is를 사용하여 __eq__()를 구현하고 잘못된 비교의 경우 NotImplemented를 반환합니다. x가 y이면 True이고 그렇지 않으면 NotImplemented입니다. __ne__()의 경우 기본적으로 __eq__()에 위임하고 NotImplemented가 아닌 한 결과를 반전시킵니다. 비교 연산자 또는 기본 구현 사이에 다른 묵시적 관계는 없습니다. 예를 들어 (x<y 또는 x==y)의 참은 x<=y를 의미하지 않습니다. 단일 루트 작업에서 순서 지정 작업을 자동으로 생성하려면 functools.total_ordering()을 참조하십시오.

사용자 지정 비교 작업을 지원하고 사전 키로 사용할 수 있는 해시 가능한 객체를 만드는 방법에 대한 몇 가지 중요한 참고 사항은 __hash__()에 대한 단락을 참조하십시오.

이러한 메서드의 교체된 인수 버전은 없습니다(왼쪽 인수는 작업을 지원하지 않지만 오른쪽 인수는 지원하는 경우 사용됨). 오히려 __lt__()와 __gt__()는 서로의 반영이고, __le__()과 __ge__()는 서로의 반영이며, __eq__()와 __ne__()은 그들 자신의 반영입니다. 피연산자의 유형이 다르고 오른쪽 피연산자의 유형이 왼쪽 피연산자 유형의 직간접 하위 클래스인 경우 오른쪽 피연산자의 반영된 메서드가 우선순위를 가지며, 그렇지 않으면 왼쪽 피연산자의 메서드가 우선순위를 갖습니다. 가상 서브클래싱은 고려되지 않습니다.

object.__hash__(self)

내장 함수 hash()에 의해 호출되며 set, frozenset 및 dict를 포함한 해시된 컬렉션의 멤버에 대한 작업을 위해 호출됩니다. __hash__() 메서드는 정수를 반환해야 합니다. 유일한 필수 속성은 동일하다고 비교되는 객체가 동일한 해시 값을 갖는다는 것입니다. 개체를 튜플로 압축하고 튜플을 해싱하여 개체 비교에서 역할을 하는 개체 구성 요소의 해시 값을 함께 혼합하는 것이 좋습니다. 예:

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

Note
 hash() truncates the value returned from an object’s custom __hash__() method to the size of a Py_ssize_t. This is typically 8 bytes on 64-bit builds and 4 bytes on 32-bit builds. If an object’s __hash__() must interoperate on builds of different bit sizes, be sure to check the width on all supported builds. An easy way to do this is with python -c "import sys; print(sys.hash_info.width)".

클래스가 __eq__() 메서드를 정의하지 않으면 __hash__() 작업도 정의해서는 안 됩니다. __eq__()를 정의하지만 __hash__()를 정의하지 않으면 해당 인스턴스는 해시 가능한 컬렉션의 항목으로 사용할 수 없습니다. 클래스가 변경 가능한 객체를 정의하고 __eq__() 메서드를 구현하는 경우 해시 가능한 컬렉션을 구현하려면 키의 해시 값이 변경 불가능해야 하기 때문에 __hash__()를 구현하면 안 됩니다(객체의 해시 값이 변경되면 잘못된 위치에 놓이게 됩니다) 해시 버킷).

사용자 정의 클래스에는 기본적으로 __eq__() 및 __hash__() 메서드가 있습니다. 그들과 함께, 모든 객체는 동등하지 않은 것을 비교하고(자신을 제외하고) x.__hash__()는 x == y가 x가 y이고 hash(x) == hash(y)임을 암시하는 적절한 값을 반환합니다.

__eq__()를 재정의하고 __hash__()를 정의하지 않는 클래스는 __hash__()가 암시적으로 없음으로 설정됩니다. 클래스의 __hash__() 메서드가 None이면 프로그램이 해시 값을 검색하려고 시도할 때 클래스의 인스턴스가 적절한 TypeError를 발생시키고 isinstance(obj, collections.abc.Hashable을 확인할 때 해시할 수 없는 것으로 올바르게 식별됩니다. ).

__eq__()를 재정의하는 클래스가 부모 클래스의 __hash__() 구현을 유지해야 하는 경우 인터프리터는 __hash__ = .__hash__를 설정하여 이를 명시적으로 알려야 합니다.

__eq__()를 재정의하지 않는 클래스가 해시 지원을 억제하려면 클래스 정의에 __hash__ = None을 포함해야 합니다. TypeError를 명시적으로 발생시키는 자체 __hash__()를 정의하는 클래스는 isinstance(obj, collections.abc.Hashable) 호출에 의해 해시 가능한 것으로 잘못 식별됩니다.

참고 기본적으로 str 및 bytes 객체의 __hash__() 값은 예측할 수 없는 임의의 값으로 “소금 처리”됩니다. 그것들은 개별 Python 프로세스 내에서 일정하게 유지되지만 반복되는 Python 호출 간에는 예측할 수 없습니다.
이는 사전 삽입의 최악의 성능인 O(n2) 복잡성을 악용하는 신중하게 선택된 입력으로 인해 발생하는 서비스 거부에 대한 보호를 제공하기 위한 것입니다. 자세한 내용은 http://www.ocert.org/advisories/ocert-2011-003.html을 참조하십시오.
해시 값을 변경하면 집합의 반복 순서에 영향을 줍니다. Python은 이 순서에 대해 보장하지 않습니다(일반적으로 32비트와 64비트 빌드 사이에서 다릅니다).
PYTHONHASHSEED도 참조하십시오.

버전 3.3에서 변경: 해시 무작위화는 기본적으로 활성화됩니다.

object.__bool__(self)

진리값 테스트 및 내장 연산 bool()을 구현하기 위해 호출됩니다. False 또는 True를 반환해야 합니다. 이 메서드가 정의되지 않은 경우 __len__()이 정의된 경우 호출되고 결과가 0이 아닌 경우 객체는 참으로 간주됩니다. 클래스가 __len__()도 __bool__()도 정의하지 않으면 모든 인스턴스가 참으로 간주됩니다.

3.3.2. Customizing attribute access

클래스 인스턴스에 대한 속성 액세스(x.name의 사용, 할당 또는 삭제)의 의미를 사용자 지정하기 위해 다음 메서드를 정의할 수 있습니다.

object.__getattr__(selfname)

기본 속성 액세스가 AttributeError와 함께 실패할 때 호출됩니다(name이 인스턴스 속성이 아니거나 self에 대한 클래스 트리의 속성이 아니기 때문에 __getattribute__()가 AttributeError를 발생시키거나 name 속성의 __get__()이 AttributeError를 발생시키기 때문). 이 메서드는 (계산된) 속성 값을 반환하거나 AttributeError 예외를 발생시켜야 합니다.

정상적인 메커니즘을 통해 속성이 발견되면 __getattr__()이 호출되지 않는다는 점에 유의하십시오. (이것은 __getattr__()과 __setattr__() 사이의 의도적인 비대칭입니다.) 이것은 효율성상의 이유와 그렇지 않으면 __getattr__()이 인스턴스의 다른 속성에 액세스할 방법이 없기 때문에 수행됩니다. 적어도 인스턴스 변수의 경우 인스턴스 속성 사전에 값을 삽입하지 않고 대신 다른 객체에 삽입하여 전체 제어를 위조할 수 있습니다. 속성 액세스를 실제로 완전히 제어하는 방법은 아래의 __getattribute__() 메서드를 참조하십시오.

object.__getattribute__(selfname)

클래스의 인스턴스에 대한 속성 액세스를 구현하기 위해 무조건 호출됩니다. 클래스가 __getattr__()도 정의하는 경우 __getattribute__()가 명시적으로 호출하거나 AttributeError를 발생시키지 않는 한 후자는 호출되지 않습니다. 이 메서드는 (계산된) 속성 값을 반환하거나 AttributeError 예외를 발생시켜야 합니다. 이 메서드에서 무한 재귀를 방지하려면 구현 시 항상 동일한 이름으로 기본 클래스 메서드를 호출하여 필요한 속성(예: object.__getattribute__(self, name))에 액세스해야 합니다.

언어 구문 또는 내장 함수를 통한 암시적 호출의 결과로 특수 메서드를 조회할 때 이 메서드는 여전히 우회될 수 있습니다. 특수 메서드 조회를 참조하세요.

특정 민감한 속성 액세스의 경우 obj 및 name 인수를 사용하여 감사 이벤트 객체.__getattr__을 발생시킵니다.

object.__setattr__(selfnamevalue)

속성 할당을 시도할 때 호출됩니다. 이것은 일반적인 메커니즘(즉, 인스턴스 사전에 값을 저장) 대신에 호출됩니다. name은 속성 이름이고 value는 할당할 값입니다.

__setattr__()이 인스턴스 어트리뷰트에 할당하려는 경우 동일한 이름을 가진 기본 클래스 메서드를 호출해야 합니다(예: object.__setattr__(self, name, value)).

특정 민감한 속성 할당의 경우 obj, name, value 인수를 사용하여 감사 이벤트 object.__setattr__을 발생시킵니다.

object.__delattr__(selfname)

__setattr__()과 비슷하지만 할당 대신 속성을 삭제합니다. 이는 del obj.name이 개체에 의미가 있는 경우에만 구현해야 합니다.

특정 민감한 속성 삭제의 경우 obj 및 name 인수를 사용하여 감사 이벤트 객체.__delattr__을 발생시킵니다.

object.__dir__(self)

객체에서 dir()이 호출될 때 호출됩니다. 시퀀스를 반환해야 합니다. dir()은 반환된 시퀀스를 목록으로 변환하고 정렬합니다.

3.3.2.1. Customizing module attribute access

특수 이름 __getattr__ 및 __dir__을 사용하여 모듈 속성에 대한 액세스를 사용자 정의할 수도 있습니다. 모듈 수준의 __getattr__ 함수는 속성의 이름인 하나의 인수를 수락하고 계산된 값을 반환하거나 AttributeError를 발생시켜야 합니다. 일반적인 조회를 통해 모듈 객체에서 속성을 찾을 수 없는 경우, 즉 object.__getattribute__(), AttributeError를 발생시키기 전에 모듈 __dict__에서 __getattr__을 검색합니다. 찾으면 속성 이름으로 호출하고 결과를 반환합니다.

__dir__ 함수는 인수를 허용하지 않고 모듈에서 액세스할 수 있는 이름을 나타내는 일련의 문자열을 반환해야 합니다. 있는 경우 이 함수는 모듈에 대한 표준 dir() 검색을 재정의합니다.

모듈 동작(속성, 속성 설정 등)을 보다 세밀하게 사용자 지정하려면 모듈 객체의 __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

정의 모듈 __getattr__ 및 설정 모듈 __class__는 어트리뷰트 액세스 구문을 사용하여 만든 조회에만 영향을 미칩니다. 모듈 전역에 직접 액세스(모듈 내의 코드를 통해 또는 모듈의 전역 사전에 대한 참조를 통해)는 영향을 받지 않습니다.

버전 3.5에서 변경: __class__ 모듈 속성은 이제 쓰기 가능합니다.

버전 3.7의 새로운 기능: __getattr__ 및 __dir__ 모듈 속성.

또한보십시오 PEP 562 – 모듈 __getattr__ 및 __dir__ 모듈의 __getattr__ 및 __dir__ 함수에 대해 설명합니다.

3.3.2.2. Implementing Descriptors

다음 메서드는 메서드를 포함하는 클래스의 인스턴스(소위 설명자 클래스)가 소유자 클래스에 나타날 때만 적용됩니다(설명자는 소유자의 클래스 사전 또는 부모 중 하나의 클래스 사전에 있어야 함). 아래 예에서 “속성”은 이름이 소유자 클래스 ‘__dict__에 있는 속성의 키인 속성을 나타냅니다.

object.__get__(selfinstanceowner=None)

소유자 클래스(클래스 속성 액세스) 또는 해당 클래스의 인스턴스(인스턴스 속성 액세스)의 속성을 가져오기 위해 호출됩니다. 선택적 소유자 인수는 소유자 클래스이고 instance는 속성에 액세스한 인스턴스이거나 소유자를 통해 속성에 액세스한 경우 None입니다.

이 메서드는 계산된 속성 값을 반환하거나 AttributeError 예외를 발생시켜야 합니다.

PEP 252는 __get__()이 하나 또는 두 개의 인수로 호출 가능하도록 지정합니다. 파이썬 자체 내장 설명자가 이 사양을 지원합니다. 그러나 일부 타사 도구에는 두 인수가 모두 필요한 설명자가 있을 수 있습니다. 파이썬 자체의 __getattribute__() 구현은 필요 여부에 관계없이 항상 두 인수를 모두 전달합니다.

object.__set__(selfinstancevalue)

소유자 클래스의 인스턴스 인스턴스에 대한 속성을 새 값인 value로 설정하기 위해 호출됩니다.

__set__() 또는 __delete__()를 추가하면 설명자의 종류가 “데이터 설명자”로 변경됩니다. 자세한 내용은 설명자 호출을 참조하십시오.

object.__delete__(selfinstance)

소유자 클래스의 인스턴스 인스턴스에서 특성을 삭제하기 위해 호출됩니다.

__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입니다. 인수가 어셈블되는 방법은 다음에 따라 다릅니다.

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__())가 정의된 데이터 디스크립터는 항상 인스턴스 사전의 재정의를 재정의합니다. 대조적으로, 비 데이터 디스크립터는 인스턴스에 의해 재정의될 수 있습니다.

Python 메서드(@staticmethod 및 @classmethod로 장식된 메서드 포함)는 비데이터 설명자로 구현됩니다. 따라서 인스턴스는 메서드를 재정의하고 재정의할 수 있습니다. 이렇게 하면 개별 인스턴스가 동일한 클래스의 다른 인스턴스와 다른 동작을 얻을 수 있습니다.

property() 함수는 데이터 설명자로 구현됩니다. 따라서 인스턴스는 속성의 동작을 재정의할 수 없습니다.

3.3.2.4. __slots__

__slots__를 사용하면 데이터 멤버(속성 등)를 명시적으로 선언하고 __dict__ 및 __weakref__ 생성을 거부할 수 있습니다(__slots__에서 명시적으로 선언하거나 부모에서 사용할 수 있는 경우 제외).

__dict__를 사용하여 절약된 공간은 상당할 수 있습니다. 속성 조회 속도도 크게 향상될 수 있습니다.

object.__slots__

이 클래스 변수는 인스턴스에서 사용되는 변수 이름이 있는 문자열, 반복 가능 또는 일련의 문자열을 할당할 수 있습니다. __slots__는 선언된 변수를 위한 공간을 예약하고 각 인스턴스에 대한 __dict__ 및 __weakref__의 자동 생성을 방지합니다.

3.3.2.4.1. Notes on using __slots__
  • __slots__가 없는 클래스에서 상속할 때 인스턴스의 __dict__ 및 __weakref__ 속성에 항상 액세스할 수 있습니다.
  • __dict__ 변수가 없으면 인스턴스에 __slots__ 정의에 나열되지 않은 새 변수를 할당할 수 없습니다. 목록에 없는 변수 이름에 할당하려고 하면 AttributeError가 발생합니다. 새 변수의 동적 할당이 필요한 경우 __slots__ 선언의 문자열 시퀀스에 ‘__dict__’를 추가합니다.
  • 각 인스턴스에 대한 __weakref__ 변수가 없으면 __slots__를 정의하는 클래스는 해당 인스턴스에 대한 약한 참조를 지원하지 않습니다. 약한 참조 지원이 필요한 경우 __slots__ 선언의 문자열 시퀀스에 ‘__weakref__’를 추가합니다.
  • __슬롯__은 각 변수 이름에 대한 설명자를 생성하여 클래스 수준에서 구현됩니다. 결과적으로 클래스 속성은 __slots__로 정의된 인스턴스 변수의 기본값을 설정하는 데 사용할 수 없습니다. 그렇지 않으면 class 속성이 설명자 할당을 덮어씁니다.
  • __slots__ 선언의 동작은 그것이 정의된 클래스로 제한되지 않습니다. 부모 클래스에서 선언된 __slots__은 자식 클래스에서 사용할 수 있습니다. 그러나 하위 하위 클래스는 __slots__(추가 슬롯의 이름만 포함해야 함)도 정의하지 않는 한 __dict__ 및 __weakref__를 가져옵니다.
  • 클래스가 기본 클래스에도 정의된 슬롯을 정의하는 경우 기본 클래스 슬롯에 의해 정의된 인스턴스 변수에 액세스할 수 없습니다(기본 클래스에서 해당 설명자를 직접 검색하는 경우 제외). 이것은 정의되지 않은 프로그램의 의미를 렌더링합니다. 향후에는 이를 방지하기 위한 검사가 추가될 수 있습니다.
  • 비어 있지 않은 __slots__는 int, bytes 및 tuple과 같은 “가변 길이” 내장 유형에서 파생된 클래스에 대해 작동하지 않습니다.
  • 문자열이 아닌 모든 iterable은 __slots__에 할당될 수 있습니다.
  • __slots__를 할당하기 위해 사전을 사용하는 경우 사전 키가 슬롯 이름으로 사용됩니다. 사전의 값은 inspect.getdoc()에서 인식하고 help()의 출력에 표시되는 속성별 docstring을 제공하는 데 사용할 수 있습니다.
  • __class__ 할당은 두 클래스가 동일한 __slots__를 가진 경우에만 작동합니다.
  • 여러 개의 슬롯이 있는 상위 클래스를 사용한 다중 상속을 사용할 수 있지만 하나의 상위만 슬롯에 의해 생성된 특성을 가질 수 있습니다(다른 기반에는 빈 슬롯 레이아웃이 있어야 함). 위반 시 TypeError가 발생합니다.
  • 반복자가 __slots__에 사용되면 각 반복자의 값에 대해 설명자가 생성됩니다. 그러나 __slots__ 속성은 빈 반복자가 됩니다.

3.3.3. Customizing class creation

클래스가 다른 클래스에서 상속될 때마다 __init_subclass__()가 부모 클래스에서 호출됩니다. 이런 식으로 하위 클래스의 동작을 변경하는 클래스를 작성할 수 있습니다. 이것은 클래스 데코레이터와 밀접하게 관련되어 있지만 클래스 데코레이터가 적용되는 특정 클래스에만 영향을 미치는 경우 __init_subclass__는 메서드를 정의하는 클래스의 향후 하위 클래스에만 적용됩니다.

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__는 아무 작업도 수행하지 않지만 인수를 사용하여 호출하면 오류가 발생합니다.

참고 메타클래스 힌트 메타클래스는 나머지 형식 기계에서 사용되며 __init_subclass__ 구현으로 전달되지 않습니다. 명시적 힌트가 아닌 실제 메타클래스는 type(cls)로 액세스할 수 있습니다.

버전 3.6의 새로운 기능.

클래스가 생성되면 type.__new__()는 클래스 변수를 스캔하고 __set_name__() 후크가 있는 변수에 대한 콜백을 만듭니다.

object.__set_name__(selfownername)

소유 클래스 소유자가 생성될 때 자동으로 호출됩니다. 개체는 해당 클래스의 이름에 할당되었습니다.

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

자세한 내용은 클래스 개체 만들기를 참조하세요.

버전 3.6의 새로운 기능.

3.3.3.1. Metaclasses

기본적으로 클래스는 type()을 사용하여 구성됩니다. 클래스 본문은 새 네임스페이스에서 실행되고 클래스 이름은 type(name, bases, namespace)의 결과에 로컬로 바인딩됩니다.

클래스 생성 프로세스는 클래스 정의 행에 메타클래스 키워드 인수를 전달하거나 그러한 인수를 포함하는 기존 클래스에서 상속하여 사용자 정의할 수 있습니다. 다음 예제에서 MyClass와 MySubclass는 모두 Meta의 인스턴스입니다.

class Meta(type):
    pass

class MyClass(metaclass=Meta):
    pass

class MySubclass(MyClass):
    pass

클래스 정의에 지정된 다른 모든 키워드 인수는 아래에 설명된 모든 메타클래스 작업으로 전달됩니다.

클래스 정의가 실행되면 다음 단계가 발생합니다.

  • MRO 항목이 해결됩니다.
  • 적절한 메타클래스가 결정됩니다.
  • 클래스 네임스페이스가 준비되었습니다.
  • 클래스 본문이 실행됩니다.
  • 클래스 개체가 생성됩니다.

3.3.3.2. Resolving MRO entries

클래스 정의에 나타나는 기반이 유형의 인스턴스가 아닌 경우 __mro_entries__ 메서드가 검색됩니다. 발견되면 원래 기본 튜플과 함께 호출됩니다. 이 메서드는 이 기본 대신 사용될 클래스의 튜플을 반환해야 합니다. 튜플은 비어 있을 수 있으며, 이 경우 원래 베이스는 무시됩니다.

PEP 560 – 타이핑 모듈 및 일반 유형에 대한 핵심 지원도 참조하십시오.

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__ 메서드는 클래스 메서드로 구현되어야 합니다. __prepare__에 의해 반환된 네임스페이스는 __new__에 전달되지만 최종 클래스 객체가 생성될 때 네임스페이스는 새 사전에 복사됩니다.

메타클래스에 __prepare__ 속성이 없으면 클래스 네임스페이스는 비어 있는 정렬된 매핑으로 초기화됩니다.

See alsoPEP 3115 – Metaclasses in Python 3000 (Introduced the __prepare__ namespace hook)

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()에서 참조할 개체입니다. __class__는 클래스 본문의 메서드가 __class__ 또는 super를 참조하는 경우 컴파일러에 의해 생성된 암시적 클로저 참조입니다. 이렇게 하면 인수가 없는 형식의 super()가 어휘 범위 지정을 기반으로 정의되는 클래스를 올바르게 식별할 수 있으며, 현재 호출을 만드는 데 사용된 클래스 또는 인스턴스는 메서드에 전달된 첫 번째 인수를 기반으로 식별됩니다.

CPython 구현 세부 정보: CPython 3.6 이상에서 __class__ 셀은 클래스 네임스페이스의 __classcell__ 항목으로 메타클래스에 전달됩니다. 있는 경우 클래스가 올바르게 초기화되려면 type.__new__ 호출까지 전파되어야 합니다. 그렇게 하지 않으면 Python 3.8에서 RuntimeError가 발생합니다.

기본 메타클래스 유형 또는 궁극적으로 type.__new__를 호출하는 메타클래스를 사용하는 경우 클래스 객체를 생성한 후 다음과 같은 추가 사용자 지정 단계가 호출됩니다.

  1. type.__new__ 메서드는 __set_name__() 메서드를 정의하는 클래스 네임스페이스의 모든 속성을 수집합니다.
  2. 이러한 __set_name__ 메서드는 정의되는 클래스와 해당 특정 속성의 할당된 이름으로 호출됩니다.
  3. __init_subclass__() 훅은 메서드 결정 순서에 따라 새 클래스의 직계 부모에서 호출됩니다.

클래스 객체가 생성되면 클래스 정의(있는 경우)에 포함된 클래스 데코레이터로 전달되고 결과 객체는 정의된 클래스로 로컬 네임스페이스에 바인딩됩니다.

type.__new__에 의해 새로운 클래스가 생성되면 네임스페이스 매개변수로 제공된 객체가 새로 정렬된 매핑에 복사되고 원래 객체는 삭제됩니다. 새 사본은 클래스 객체의 __dict__ 속성이 되는 읽기 전용 프록시로 래핑됩니다.

See also
PEP 3135 – New super (Describes the implicit __class__ closure reference)

3.3.3.7. Uses for metaclasses

메타클래스의 잠재적 용도는 무한합니다. 탐색된 몇 가지 아이디어에는 열거형, 로깅, 인터페이스 검사, 자동 위임, 자동 속성 생성, 프록시, 프레임워크 및 자동 리소스 잠금/동기화가 포함됩니다.

3.3.4. Customizing instance and subclass checks

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

특히 메타클래스 abc.ABCMeta는 다른 ABC를 포함하여 모든 클래스 또는 유형(내장 유형 포함)에 “가상 기본 클래스”로 ABC(추상 기본 클래스)를 추가할 수 있도록 이러한 메서드를 구현합니다.

class.__instancecheck__(selfinstance)

인스턴스가 클래스의 (직접 또는 간접) 인스턴스로 간주되어야 하는 경우 true를 반환합니다. 정의된 경우 isinstance(instance, class)를 구현하기 위해 호출됩니다.

class.__subclasscheck__(selfsubclass)

하위 클래스가 클래스의 (직접 또는 간접) 하위 클래스로 간주되어야 하는 경우 true를 반환합니다. 정의된 경우 issubclass(subclass, class)를 구현하기 위해 호출됩니다.

이러한 메서드는 클래스의 유형(메타클래스)에서 조회됩니다. 실제 클래스에서 클래스 메서드로 정의할 수 없습니다. 이는 인스턴스에서 호출되는 특수 메서드 조회와 일치하며, 이 경우에만 인스턴스 자체가 클래스입니다.

See also: PEP 3119 – Introducing Abstract Base Classes
__instancecheck__() 및 __subclasscheck__()를 통해 isinstance() 및 issubclass() 동작을 사용자 지정하기 위한 사양을 포함하며, 언어에 추상 기본 클래스(abc 모듈 참조)를 추가하는 맥락에서 이 기능에 대한 동기를 부여합니다.

3.3.5. Emulating generic types

유형 주석을 사용할 때 Python의 대괄호 표기법을 사용하여 일반 유형을 매개변수화하는 것이 종종 유용합니다. 예를 들어 list[int] 주석은 모든 요소가 int 유형인 목록을 나타내는 데 사용될 수 있습니다.

See also
PEP 484 – Type Hints
유형 주석을 위한 Python 프레임워크 소개
Generic Alias Types
매개변수화된 제네릭 클래스를 나타내는 개체에 대한 설명서
Genericsuser-defined generics and typing.Generic
런타임에 매개변수화할 수 있고 정적 유형 검사기가 이해할 수 있는 제네릭 클래스를 구현하는 방법에 대한 문서입니다.

클래스는 일반적으로 특수 클래스 메서드 __class_getitem__()을 정의하는 경우에만 매개 변수화할 수 있습니다.

classmethod object.__class_getitem__(clskey)

키에서 찾은 유형 인수로 일반 클래스의 특수화를 나타내는 객체를 반환합니다.

클래스에 정의된 경우 __class_getitem__()은 자동으로 클래스 메서드입니다. 따라서 정의할 때 @classmethod로 장식할 필요가 없습니다.

3.3.5.1. The purpose of __class_getitem__

__class_getitem__() 의 목적은 이러한 클래스에 유형 힌트를 더 쉽게 적용하기 위해 표준 라이브러리 일반 클래스의 런타임 매개변수화를 허용하는 것입니다.

런타임에 매개변수화할 수 있고 정적 유형 검사기가 이해할 수 있는 사용자 지정 제네릭 클래스를 구현하려면 사용자는 이미 __class_getitem__()을 구현하는 표준 라이브러리 클래스에서 상속하거나 __class_getitem__(의 자체 구현이 있는 typing.Generic에서 상속해야 합니다. ).

표준 라이브러리 외부에서 정의된 클래스에 대한 __class_getitem__()의 사용자 정의 구현은 mypy와 같은 타사 유형 검사기에서 이해하지 못할 수 있습니다. 유형 힌트 이외의 목적으로 모든 클래스에서 __class_getitem__() 을 사용하는 것은 권장되지 않습니다.

3.3.5.2. __class_getitem__ versus __getitem__

일반적으로 대괄호를 사용한 객체 구독은 객체의 클래스에 정의된 __getitem__() 인스턴스 메서드를 호출합니다. 그러나 구독 중인 개체 자체가 클래스인 경우 클래스 메서드 __class_getitem__()이 대신 호출될 수 있습니다. __class_getitem__()은 적절하게 정의된 경우 GenericAlias 객체를 반환해야 합니다.

표현식 obj[x]와 함께 제공되는 파이썬 인터프리터는 다음 프로세스와 같은 것을 따라 __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은 __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 – 타이핑 모듈 및 제네릭 유형에 대한 핵심 지원
__class_getitem__() 소개 및 구독으로 인해 __getitem__() 대신 __class_getitem__()이 호출되는 경우 개요

3.3.6. Emulating callable objects

object.__call__(self[, args…])

인스턴스가 함수로 “호출”될 때 호출됩니다. 이 메서드가 정의된 경우 x(arg1, arg2, …)는 대략 type(x).__call__(x, arg1, …)으로 변환됩니다.

3.3.7. Emulating container types

컨테이너 개체를 구현하기 위해 다음 메서드를 정의할 수 있습니다. 컨테이너는 일반적으로 시퀀스(예: 목록 또는 튜플) 또는 매핑(예: 사전)이지만 다른 컨테이너도 나타낼 수 있습니다. 첫 번째 메서드 집합은 시퀀스를 에뮬레이트하거나 매핑을 에뮬레이트하는 데 사용됩니다. 차이점은 시퀀스의 경우 허용 가능한 키는 0 <= k < N인 정수 k(여기서 N은 시퀀스의 길이 또는 항목 범위를 정의하는 슬라이스 개체)여야 한다는 것입니다. 또한 매핑이 동작하는 메서드 keys(), values(), items(), get(), clear(), setdefault(), pop(), popitem(), copy() 및 update() 메서드를 제공하는 것이 좋습니다. Python의 표준 사전 객체와 유사합니다. collections.abc 모듈은 MutableMapping 추상 기본 클래스를 제공하여 __getitem__(), __setitem__(), __delitem__() 및 keys()의 기본 집합에서 해당 메서드를 만드는 데 도움을 줍니다. 변경 가능한 시퀀스는 Python 표준 목록 객체와 같은 메소드 append(), count(), index(), extend(), insert(), pop(), remove(), reverse() 및 sort()를 제공해야 합니다. 마지막으로 시퀀스 유형은 아래에 설명된 __add__(), __radd__(), __iadd__(), __mul__(), __rmul__() 및 __imul__() 메서드를 정의하여 덧셈(연결을 의미) 및 곱셈(반복을 의미)을 구현해야 합니다. 다른 숫자 연산자를 정의하면 안 됩니다. in 연산자를 효율적으로 사용할 수 있도록 매핑과 시퀀스 모두 __contains__() 메서드를 구현하는 것이 좋습니다. 매핑의 경우 in은 매핑의 키를 검색해야 합니다. 시퀀스의 경우 값을 통해 검색해야 합니다. 또한 매핑과 시퀀스 모두 __iter__() 메서드를 구현하여 컨테이너 전체를 효율적으로 반복할 수 있도록 하는 것이 좋습니다. 매핑의 경우 __iter__() 는 객체의 키를 통해 반복해야 합니다. 시퀀스의 경우 값을 반복해야 합니다.

object.__len__(self)

내장 함수 len()을 구현하기 위해 호출됩니다. 객체의 길이, 정수 >= 0을 반환해야 합니다. 또한 __bool__() 메서드를 정의하지 않고 __len__() 메서드가 0을 반환하는 객체는 부울 컨텍스트에서 거짓으로 간주됩니다.

CPython 구현 세부 정보: CPython에서 길이는 최대 sys.maxsize여야 합니다. 길이가 sys.maxsize보다 크면 일부 기능(예: len())이 OverflowError를 일으킬 수 있습니다. 진리값 테스트로 OverflowError가 발생하는 것을 방지하려면 객체가 __bool__() 메서드를 정의해야 합니다.

object.__length_hint__(self)

operator.length_hint()를 구현하기 위해 호출됩니다. 개체의 예상 길이를 반환해야 합니다(실제 길이보다 크거나 작을 수 있음). 길이는 정수 >= 0이어야 합니다. 반환 값은 NotImplemented일 수도 있으며, 이는 __length_hint__ 메서드가 전혀 존재하지 않는 것과 동일하게 취급됩니다. 이 방법은 순전히 최적화이며 정확성을 위해 필요하지 않습니다.

버전 3.4의 새로운 기능.

참고: 슬라이싱은 다음 세 가지 방법으로 독점적으로 수행됩니다.
다음과 같은 호출은:

a[1:2] = b

아래와 같이 해석됩니다.

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

기타 등등. 누락된 슬라이스 항목은 항상 None으로 채워집니다.

object.__getitem__(selfkey)

self[key] 평가를 구현하기 위해 호출됩니다. 시퀀스 유형의 경우 허용되는 키는 정수 및 슬라이스 객체여야 합니다. 음수 인덱스의 특별한 해석(클래스가 시퀀스 유형을 에뮬레이트하려는 경우)은 __getitem__() 메서드에 달려 있음에 유의하십시오. 키가 부적절한 유형이면 TypeError가 발생할 수 있습니다. 시퀀스에 대한 인덱스 집합 외부의 값인 경우(음수 값의 특수 해석 후), IndexError 가 발생해야 합니다. 매핑 유형의 경우 키가 누락된 경우(컨테이너에 없음) KeyError가 발생해야 합니다.

참고: for 루프는 시퀀스의 끝을 적절하게 감지할 수 있도록 잘못된 인덱스에 대해 IndexError가 발생할 것으로 예상합니다.

참고: 클래스를 첨자로 작성할 때 __getitem__() 대신 특수 클래스 메서드 __class_getitem__()을 호출할 수 있습니다. 자세한 내용은 __class_getitem__versus__getitem__을 참조하십시오.

object.__setitem__(selfkeyvalue)

self[key]에 대한 할당을 구현하기 위해 호출됩니다. __getitem__()과 동일한 참고 사항입니다. 개체가 키 값에 대한 변경을 지원하거나 새 키를 추가할 수 있는 경우 또는 요소를 교체할 수 있는 경우 시퀀스에 대해 매핑에 대해서만 구현해야 합니다. __getitem__() 메서드에 대해 부적절한 키 값에 대해 동일한 예외가 발생해야 합니다.

object.__delitem__(selfkey)

self[key] 삭제를 구현하기 위해 호출됩니다. __getitem__()과 동일한 참고 사항입니다. 개체가 키 제거를 지원하는 경우 매핑에 대해서만 구현하거나 시퀀스에서 요소를 제거할 수 있는 경우 시퀀스에 대해 구현해야 합니다. __getitem__() 메서드에 대해 부적절한 키 값에 대해 동일한 예외가 발생해야 합니다.

object.__missing__(selfkey)

key가 딕셔너리에 없을 때 dict 하위 클래스에 대해 self[key]를 구현하기 위해 dict.__getitem__()에 의해 호출됩니다.

object.__iter__(self)

이 메서드는 컨테이너에 iterator가 필요할 때 호출됩니다. 이 메서드는 컨테이너의 모든 개체를 반복할 수 있는 새 iterator 개체를 반환해야 합니다. Mapping의 경우 컨테이너의 키를 반복해야 합니다.

object.__reversed__(self)

역방향 반복을 구현하기 위해 reversed() 내장에 의해 호출됩니다(있는 경우). 컨테이너의 모든 개체를 역순으로 반복하는 새 반복자 개체를 반환해야 합니다.

__reversed__() 메서드가 제공되지 않으면, reversed() 내장은 시퀀스 프로토콜(__len__() 및 __getitem__())을 사용하도록 대체됩니다. 시퀀스 프로토콜을 지원하는 객체는 reversed()에서 제공하는 것보다 더 효율적인 구현을 제공할 수 있는 경우에만 __reversed__()를 제공해야 합니다.

멤버십 테스트 연산자(in 및 not in)는 일반적으로 컨테이너를 통한 반복으로 구현됩니다. 그러나 컨테이너 개체는 개체가 반복 가능할 필요가 없는 보다 효율적인 구현으로 다음과 같은 특수 메서드를 제공할 수 있습니다.

object.__contains__(selfitem)

멤버십 테스트 연산자를 구현하기 위해 호출됩니다. item이 self에 있으면 true를 반환하고 그렇지 않으면 false를 반환해야 합니다. 매핑 개체의 경우 값이나 key-item 쌍이 아닌 매핑의 키를 고려해야 합니다.

__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(), **, <<, >>, &, ^, |)을 구현하기 위해 호출됩니다. 예를 들어, 표현식 x + y를 평가하려면 여기서 x는 __add__() 메서드가 있는 클래스의 인스턴스이고 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 예를 들어, 표현식 x – y를 평가하기 위해 y는 __rsub__() 메서드가 있는 클래스의 인스턴스이고, type(y).__rsub__(y, x)는 type(x).__sub__(x , y)는 NotImplemented를 반환합니다.

삼항 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 += y는 x = x.__iadd__(y) 와 동일합니다. 그렇지 않으면 x + y의 평가와 마찬가지로 x.__add__(y) 및 y.__radd__(x)가 고려됩니다. 특정 상황에서 증강 할당은 예기치 않은 오류를 유발할 수 있지만(왜 a_tuple[i] += [‘item’]이 추가가 작동할 때 예외를 발생시키나요? 참조) 이 동작은 사실 데이터 모델의 일부입니다.

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() 함수에서). 이 메서드가 있으면 숫자 개체가 정수 유형임을 나타냅니다. 정수를 반환해야 합니다.

__int__(), __float__() 및 __complex__()가 정의되지 않은 경우 해당 내장 함수 int(), float() 및 complex()는 __index__()로 대체됩니다.

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

내장 함수 round() 및 수학 함수 trunc(), floor() 및 ceil()을 구현하기 위해 호출됩니다. ndigits가 __round__()에 전달되지 않는 한 이 모든 메서드는 Integral(일반적으로 int)으로 잘린 객체의 값을 반환해야 합니다.

내장 함수 int()는 __int__()도 __index__()도 정의되지 않은 경우 __trunc__()로 돌아갑니다.

버전 3.11에서 변경: int()에서 __trunc__()로의 위임은 더 이상 사용되지 않습니다.

3.3.9. With Statement Context Managers

컨텍스트 관리자는 with 문을 실행할 때 설정할 런타임 컨텍스트를 정의하는 객체입니다. 컨텍스트 관리자는 코드 블록 실행을 위해 원하는 런타임 컨텍스트로의 진입과 종료를 처리합니다. 컨텍스트 관리자는 일반적으로 with 문(with 문 섹션에서 설명)을 사용하여 호출되지만 메서드를 직접 호출하여 사용할 수도 있습니다.

컨텍스트 관리자의 일반적인 용도에는 다양한 종류의 전역 상태 저장 및 복원, 리소스 잠금 및 잠금 해제, 열린 파일 닫기 등이 포함됩니다.

컨텍스트 관리자에 대한 자세한 내용은 컨텍스트 관리자 유형을 참조하세요.

object.__enter__(self)

이 개체와 관련된 런타임 컨텍스트를 입력합니다. with 문은 이 메서드의 반환 값을 문의 as 절에 지정된 대상(있는 경우)에 바인딩합니다.

object.__exit__(selfexc_typeexc_valuetraceback)

이 개체와 관련된 런타임 컨텍스트를 종료합니다. 매개변수는 컨텍스트를 종료하게 만든 예외를 설명합니다. 컨텍스트가 예외 없이 종료된 경우 세 인수 모두 None이 됩니다.

예외가 제공되고 메서드가 예외를 억제하려는 경우(즉, 전파되지 않도록 방지) true 값을 반환해야 합니다. 그렇지 않으면 이 메서드를 종료할 때 예외가 정상적으로 처리됩니다.

__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”)인 경우 MyClass(x, y) 케이스는 MyClass(left=x, center=y) 케이스와 동일합니다. 패턴의 인수 수는 __match_args__의 요소 수보다 작거나 같아야 합니다. 더 크면 패턴 일치 시도에서 TypeError가 발생합니다.

버전 3.10의 새로운 기능.

See also: PEP 634 – Structural Pattern Matching
Python match 문에 대한 사양입니다.

3.3.11. 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 

이러한 방식으로 클래스의 바인딩되지 않은 메서드를 잘못 호출하려고 시도하는 것을 ‘메타클래스 혼동’이라고 하며 특수 메서드를 찾을 때 인스턴스를 우회하여 피할 수 있습니다.

>>> 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()으로 데코레이트된 제너레이터에서 반환된 제너레이터 이터레이터 객체도 어웨이터블이지만 __await__()를 구현하지는 않습니다.

object.__await__(self)

반복자를 반환해야 합니다. 대기 가능한 개체를 구현하는 데 사용해야 합니다. 예를 들어, asyncio.Future는 await 표현식과 호환되도록 이 메서드를 구현합니다.

참고: 이 언어는 __await__에 의해 반환된 반복자가 생성한 객체의 유형이나 값에 제한을 두지 않습니다. 이는 대기 가능한 객체를 관리할 비동기 실행 프레임워크(예: asyncio)의 구현에 고유하기 때문입니다.

버전 3.5의 새로운 기능.

See also

대기 가능한 객체에 대한 추가 정보는 PEP 492를 참조하십시오.

3.4.2. Coroutine Objects

코루틴 객체는 어웨이터블 객체입니다. 코루틴의 실행은 __await__()를 호출하고 결과를 반복하여 제어할 수 있습니다. 코루틴이 실행을 마치고 반환하면 반복자는 StopIteration을 발생시키고 예외의 값 속성은 반환 값을 보유합니다. 코루틴이 예외를 발생시키면 반복자에 의해 전파됩니다. 코루틴은 처리되지 않은 StopIteration 예외를 직접 발생시키지 않아야 합니다.

코루틴에는 또한 생성기의 메서드와 유사한 아래 나열된 메서드가 있습니다(Generator-iterator 메서드 참조). 그러나 제너레이터와 달리 코루틴은 반복을 직접 지원하지 않습니다.

버전 3.5.2에서 변경: 코루틴에서 두 번 이상 기다리는 것은 RuntimeError입니다.

coroutine.send(value)

코루틴 실행을 시작하거나 재개합니다. 값이 없음이면, 이것은 __await__()에 의해 반환된 이터레이터를 진행시키는 것과 같습니다. 값이 None이 아니면 이 메서드는 코루틴을 일시 중단하게 만든 반복자의 send() 메서드에 위임합니다. 결과(반환 값, StopIteration 또는 기타 예외)는 위에서 설명한 __await__() 반환 값을 반복할 때와 동일합니다.

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

코루틴에서 지정된 예외를 발생시킵니다. 이 메서드는 해당 메서드가 있는 경우 코루틴을 일시 중단하게 만든 반복자의 throw() 메서드에 위임합니다. 그렇지 않으면 일시 중단 지점에서 예외가 발생합니다. 결과(반환 값, StopIteration 또는 기타 예외)는 위에서 설명한 await() 반환 값을 반복할 때와 동일합니다. 코루틴에서 예외가 포착되지 않으면 호출자에게 다시 전파됩니다.

coroutine.close()

코루틴이 스스로 정리하고 종료하도록 합니다. 코루틴이 정지된 경우 이 메서드는 먼저 코루틴을 정지시킨 반복자의 close() 메서드(해당 메서드가 있는 경우)에 위임합니다. 그런 다음 중단 지점에서 GeneratorExit를 발생시켜 코루틴이 즉시 스스로 정리하도록 합니다. 마지막으로 코루틴은 시작되지 않았더라도 실행이 완료된 것으로 표시됩니다.

코루틴 객체는 파괴되려고 할 때 위의 프로세스를 사용하여 자동으로 닫힙니다.

3.4.3. Asynchronous Iterators

비동기 이터레이터는 __anext__ 메서드에서 비동기 코드를 호출할 수 있습니다.

비동기 반복자는 async for 문에서 사용할 수 있습니다.

object.__aiter__(self)

비동기 이터레이터 객체를 반환해야 합니다.

object.__anext__(self)

Iterator의 다음 값을 결과로 나타내는 awaitable을 반환해야 합니다. 반복이 끝나면 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.7에서 변경: Python 3.7 이전에는 __aiter__() 가 비동기 이터레이터로 확인되는 어웨이터블을 반환할 수 있었습니다.

파이썬 3.7부터 __aiter__()는 비동기 이터레이터 객체를 반환해야 합니다. 다른 것을 반환하면 TypeError 오류가 발생합니다.

3.4.4. Asynchronous Context Managers

비동기 컨텍스트 관리자는 __aenter__ 및 __aexit__ 메서드에서 실행을 일시 중단할 수 있는 컨텍스트 관리자입니다.

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

object.__aenter__(self)

__enter__()와 의미상 유사하지만 어웨이터블을 반환해야 한다는 유일한 차이점이 있습니다.

object.__aexit__(selfexc_typeexc_valuetraceback)

어웨이터블을 반환해야 한다는 점만 제외하면 __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의 새로운 기능.

Source: https://docs.python.org/3/reference/datamodel.html

Python Language Reference > 2. Lexical analysis

파이썬 프로그램은 파서에 의해 읽혀집니다. 구문 분석기에 대한 입력은 어휘 분석기에 의해 생성된 토큰 스트림입니다. 이 장에서는 어휘 분석기가 파일을 토큰으로 나누는 방법을 설명합니다.

Python은 프로그램 텍스트를 유니코드 코드 포인트로 읽습니다. 소스 파일의 인코딩은 인코딩 선언으로 지정할 수 있으며 기본값은 UTF-8입니다. 자세한 내용은 PEP 3120을 참조하십시오. 소스 파일을 디코딩할 수 없으면 SyntaxError가 발생합니다.

2.1. Line structure

Python 프로그램은 여러 논리적 라인으로 나뉩니다.

2.1.1. Logical lines

논리적 줄의 끝은 토큰 NEWLINE으로 표시됩니다. 명령문은 구문에서 NEWLINE이 허용되는 경우(예: 복합 명령문의 명령문 사이)를 제외하고 논리적 라인 경계를 넘을 수 없습니다. 논리 회선은 명시적 또는 암시적 회선 결합 규칙에 따라 하나 이상의 물리적 회선에서 구성됩니다.

2.1.2. Physical lines

물리적 줄은 줄 끝 순서로 끝나는 일련의 문자입니다. 소스 파일 및 문자열에서 표준 플랫폼 라인 종료 시퀀스를 사용할 수 있습니다. ASCII LF(줄 바꿈)를 사용하는 Unix 형식, ASCII 시퀀스 CR LF(리턴 다음에 줄 바꿈)를 사용하는 Windows 형식 또는 ASCII CR(리턴) 문자. 이 모든 양식은 플랫폼에 관계없이 동일하게 사용할 수 있습니다. 입력의 끝은 최종 물리적 라인에 대한 암시적 종결자 역할도 합니다.

Python을 포함할 때 줄 바꿈 문자에 대한 표준 C 규칙을 사용하여 소스 코드 문자열을 Python API에 전달해야 합니다(ASCII LF를 나타내는 \n 문자는 줄 종결자임).

2.1.3. Comments

주석은 문자열 리터럴의 일부가 아닌 해시 문자(#)로 시작하여 실제 행의 끝에서 끝납니다. 주석은 암시적 줄 결합 규칙이 호출되지 않는 한 논리 줄의 끝을 나타냅니다. 주석은 구문에서 무시됩니다.

2.1.4. Encoding declarations

Python 스크립트의 첫 번째 또는 두 번째 줄에 있는 주석이 정규식 coding[=:]\s*([-\w.]+)과 일치하면 이 주석은 인코딩 선언으로 처리됩니다. 이 식의 첫 번째 그룹은 소스 코드 파일의 인코딩 이름을 지정합니다. 인코딩 선언은 자체 줄에 나타나야 합니다. 두 번째 줄인 경우 첫 번째 줄도 주석 전용 줄이어야 합니다. 인코딩 표현식의 권장 형식은 다음과 같습니다.

# -*- coding: <encoding-name> -*-

GNU Emacs에서도 인정하는

# vim:fileencoding=<encoding-name>

Bram Moolenaar의 VIM에서 인정합니다.

인코딩 선언이 없으면 기본 인코딩은 UTF-8입니다. 또한 파일의 첫 번째 바이트가 UTF-8 바이트 순서 표시(b’\xef\xbb\xbf’)인 경우 선언된 파일 인코딩은 UTF-8입니다. ).

인코딩이 선언되면 인코딩 이름은 Python에서 인식되어야 합니다(표준 인코딩 참조). 인코딩은 문자열 리터럴, 주석 및 식별자를 포함한 모든 어휘 분석에 사용됩니다.

2.1.5. Explicit line joining

다음과 같이 백슬래시 문자()를 사용하여 두 개 이상의 물리적 라인을 논리적 라인으로 결합할 수 있습니다. 물리적 라인이 문자열 리터럴 또는 주석의 일부가 아닌 백슬래시로 끝나는 경우 단일 논리적 라인을 형성하는 다음과 결합됩니다. 백슬래시와 다음 줄 끝 문자를 삭제합니다. 예를 들어:

if 1900 < year < 2100 and 1 <= month <= 12 \
   and 1 <= day <= 31 and 0 <= hour < 24 \
   and 0 <= minute < 60 and 0 <= second < 60:   # Looks like a valid date
        return 1

백슬래시로 끝나는 줄에는 주석을 달 수 없습니다. 백슬래시는 주석을 계속하지 않습니다. 백슬래시는 문자열 리터럴을 제외하고는 토큰을 계속하지 않습니다. 백슬래시는 문자열 리터럴 외부 라인의 다른 곳에서는 불법입니다.

2.1.6. Implicit line joining

괄호, 대괄호 또는 중괄호 안의 표현식은 백슬래시를 사용하지 않고 둘 이상의 실제 행으로 분할될 수 있습니다. 예를 들어:

month_names = ['Januari', 'Februari', 'Maart',      # These are the
               'April',   'Mei',      'Juni',       # Dutch names
               'Juli',    'Augustus', 'September',  # for the months
               'Oktober', 'November', 'December']   # of the year

암시적으로 계속되는 줄은 주석을 포함할 수 있습니다. 이어지는 줄의 들여쓰기는 중요하지 않습니다. 빈 연속 줄이 허용됩니다. 암시적 연속 행 사이에는 NEWLINE 토큰이 없습니다. 암묵적으로 연속된 행은 삼중 따옴표 문자열 내에서도 발생할 수 있습니다(아래 참조). 이 경우 주석을 전달할 수 없습니다.

2.1.7. Blank lines

공백, 탭, 폼피드 및 가능하면 주석만 포함하는 논리 행은 무시됩니다(예: NEWLINE 토큰이 생성되지 않음). 문을 대화식으로 입력하는 동안 빈 줄 처리는 read-eval-print 루프의 구현에 따라 다를 수 있습니다. 표준 인터랙티브 인터프리터에서 완전히 비어 있는 논리적 줄(즉, 공백이나 주석도 포함하지 않는 줄)은 여러 줄 문을 종료합니다.

2.1.8. Indentation

논리적 줄의 시작 부분에 있는 선행 공백(공백 및 탭)은 줄의 들여쓰기 수준을 계산하는 데 사용되며, 차례로 명령문 그룹화를 결정하는 데 사용됩니다.

탭은 (왼쪽에서 오른쪽으로) 1에서 8개의 공백으로 대체되어 대체 문자까지 포함하여 총 문자 수가 8의 배수가 됩니다(이는 Unix에서 사용되는 것과 동일한 규칙입니다). 공백이 아닌 첫 번째 문자 앞의 총 공백 수는 줄의 들여쓰기를 결정합니다. 들여쓰기는 백슬래시를 사용하여 여러 줄로 나눌 수 없습니다. 첫 번째 백슬래시까지의 공백이 들여쓰기를 결정합니다.

공백에 있는 탭의 가치에 따라 의미가 달라지는 방식으로 소스 파일이 탭과 공백을 혼합하는 경우 들여쓰기가 일관성이 없는 것으로 거부됩니다. 이 경우 TabError가 발생합니다.

크로스 플랫폼 호환성 참고: 비 UNIX 플랫폼의 텍스트 편집기 특성 때문에 단일 소스 파일에서 들여쓰기에 공백과 탭을 혼합하여 사용하는 것은 현명하지 않습니다. 또한 플랫폼에 따라 최대 들여쓰기 수준을 명시적으로 제한할 수 있습니다.

줄의 시작 부분에 용지 공급 문자가 있을 수 있습니다. 위의 들여쓰기 계산에서는 무시됩니다. 선행 공백의 다른 위치에서 발생하는 용지 공급 문자는 정의되지 않은 영향을 미칩니다(예를 들어 공백 수를 0으로 재설정할 수 있음).

연속된 줄의 들여쓰기 수준은 다음과 같이 스택을 사용하여 INDENT 및 DEDENT 토큰을 생성하는 데 사용됩니다.

파일의 첫 번째 줄을 읽기 전에 단일 0이 스택에 푸시됩니다. 이것은 다시는 터지지 않을 것입니다. 스택에 푸시된 숫자는 항상 아래에서 위로 엄격하게 증가합니다. 각 논리 줄의 시작 부분에서 줄의 들여쓰기 수준을 스택의 맨 위 수준과 비교합니다. 같으면 아무 일도 일어나지 않습니다. 더 크면 스택에 푸시되고 하나의 INDENT 토큰이 생성됩니다. 더 작은 경우 스택에서 발생하는 숫자 중 하나여야 합니다. 더 큰 스택의 모든 숫자가 제거되고, 제거된 각 숫자에 대해 DEDENT 토큰이 생성됩니다. 파일 끝에서 0보다 큰 스택에 남아 있는 각 숫자에 대해 DEDENT 토큰이 생성됩니다.

다음은 올바르게(혼란스럽긴 하지만) 들여쓰기된 Python 코드의 예입니다.

def perm(l):
        # Compute the list of all permutations of l
    if len(l) <= 1:
                  return [l]
    r = []
    for i in range(len(l)):
             s = l[:i] + l[i+1:]
             p = perm(s)
             for x in p:
              r.append(l[i:i+1] + x)
    return r

다음 예는 다양한 들여쓰기 오류를 보여줍니다.

def perm(l):                       # error: first line indented
for i in range(len(l)):             # error: not indented
    s = l[:i] + l[i+1:]
        p = perm(l[:i] + l[i+1:])   # error: unexpected indent
        for x in p:
                r.append(l[i:i+1] + x)
            return r                # error: inconsistent dedent

(실제로 처음 세 개의 오류는 파서에 의해 감지됩니다. 마지막 오류만 어휘 분석기에 의해 발견됩니다. return r의 들여쓰기는 스택에서 팝된 수준과 일치하지 않습니다.)

2.1.9. Whitespace between tokens

논리적 줄의 시작 부분이나 문자열 리터럴을 제외하고 공백 문자 공백, 탭 및 양식 공급을 상호 교환하여 토큰을 구분할 수 있습니다. 두 토큰의 연결이 다른 토큰으로 해석될 수 있는 경우에만 두 토큰 사이에 공백이 필요합니다(예: ab는 하나의 토큰이지만 a b는 두 개의 토큰).

2.2. Other tokens

NEWLINE, INDENT 및 DEDENT 외에도 식별자, 키워드, 리터럴, 연산자 및 구분 기호와 같은 토큰 범주가 있습니다. 공백 문자(앞서 설명한 줄 종결자 제외)는 토큰이 아니지만 토큰을 구분하는 역할을 합니다. 모호성이 존재하는 경우 토큰은 왼쪽에서 오른쪽으로 읽을 때 합법적인 토큰을 형성하는 가능한 가장 긴 문자열로 구성됩니다.

2.3. Identifiers and keywords

식별자(이름이라고도 함)는 다음 어휘 정의로 설명됩니다.

Python의 식별자 구문은 유니코드 표준 부속서 UAX-31을 기반으로 하며 아래에 정의된 대로 정교화 및 변경됩니다. 자세한 내용은 PEP 3131도 참조하십시오.

ASCII 범위(U+0001..U+007F) 내에서 식별자에 유효한 문자는 Python 2.x에서와 동일합니다. 대문자와 소문자 A~Z, 밑줄 _ 및 첫 번째 문자를 제외하고 0에서 9까지의 숫자.

Python 3.0은 ASCII 범위 밖의 추가 문자를 도입합니다(PEP 3131 참조). 이러한 문자의 경우 분류에서는 unicodedata 모듈에 포함된 유니코드 문자 데이터베이스 버전을 사용합니다.

식별자는 길이에 제한이 없습니다. 대소문자가 중요합니다.

identifier   ::=  xid_start xid_continue*
id_start     ::=  <all characters in general categories Lu, Ll, Lt, Lm, Lo, Nl, the underscore, and characters with the Other_ID_Start property>
id_continue  ::=  <all characters in id_start, plus characters in the categories Mn, Mc, Nd, Pc and others with the Other_ID_Continue property>
xid_start    ::=  <all characters in id_start whose NFKC normalization is in "id_start xid_continue*">
xid_continue ::=  <all characters in id_continue whose NFKC normalization is in "id_continue*">

위에서 언급한 유니코드 범주 코드는 다음을 나타냅니다.

  • 루 – 대문자
  • Ll – 소문자
  • Lt – 제목 글자
  • Lm – 수정자 문자
  • Lo – 다른 문자
  • Nl – 문자 숫자
  • Mn – 비공백 표시
  • Mc – 간격 결합 표시
  • Nd – 십진수
  • PC – 커넥터 구두점
  • Other_ID_Start – 이전 버전과의 호환성을 지원하기 위한 PropList.txt의 명시적 문자 목록
  • Other_ID_Continue – 마찬가지로

모든 식별자는 구문 분석하는 동안 일반 형식 NFKC로 변환됩니다. 식별자 비교는 NFKC를 기반으로 합니다.

유니코드 14.0.0에 대한 모든 유효한 식별자 문자를 나열하는 비표준 HTML 파일은 https://www.unicode.org/Public/14.0.0/ucd/DerivedCoreProperties.txt에서 찾을 수 있습니다.

2.3.1. Keywords

다음 식별자는 언어의 예약어 또는 키워드로 사용되며 일반 식별자로 사용할 수 없습니다. 여기에 쓰여진 대로 정확히 철자를 입력해야 합니다.

False      await      else       import     pass
None       break      except     in         raise
True       class      finally    is         return
and        continue   for        lambda     try
as         def        from       nonlocal   while
assert     del        global     not        with
async      elif       if         or         yield

2.3.2. Soft Keywords

버전 3.10의 새로운 기능.

일부 식별자는 특정 컨텍스트에서만 예약됩니다. 이를 소프트 키워드라고 합니다. 식별자 match, case 및 _는 패턴 일치 문과 관련된 컨텍스트에서 키워드로 구문적으로 작동할 수 있지만 이러한 구분은 토큰화할 때가 아니라 구문 분석기 수준에서 수행됩니다.

소프트 키워드로서 일치, 대소문자 및 _를 식별자 이름으로 사용하는 기존 코드와의 호환성을 유지하면서 패턴 일치와 함께 사용할 수 있습니다.

2.3.3. Reserved classes of identifiers

특정 클래스의 식별자(키워드 제외)에는 특별한 의미가 있습니다. 이러한 클래스는 선행 및 후행 밑줄 문자 패턴으로 식별됩니다.

_*
from module import *로 가져오지 않았습니다.

_
일치 문 내의 사례 패턴에서 _는 와일드카드를 나타내는 소프트 키워드입니다.

별도로 대화형 인터프리터는 마지막 평가 결과를 변수 _에서 사용할 수 있도록 합니다. (print와 같은 내장 함수와 함께 builtins 모듈에 저장됩니다.)

다른 곳에서 _는 일반 식별자입니다. “특별한” 항목의 이름을 지정하는 데 자주 사용되지만 Python 자체에는 특별하지 않습니다.

참고: _라는 이름은 종종 국제화와 함께 사용됩니다. 이 규칙에 대한 자세한 내용은 gettext 모듈에 대한 설명서를 참조하십시오.
또한 일반적으로 사용되지 않는 변수에 사용됩니다.

__*__
비공식적으로 “dunder” 이름으로 알려진 시스템 정의 이름. 이러한 이름은 인터프리터와 그 구현(표준 라이브러리 포함)에 의해 정의됩니다. 현재 시스템 이름은 특수 메서드 이름 섹션 및 다른 곳에서 설명합니다. 향후 버전의 Python에서 더 많이 정의될 것입니다. 명시적으로 문서화된 사용을 따르지 않는 어떤 맥락에서든 이름을 사용하면 경고 없이 손상될 수 있습니다.

__*
클래스 비공개 이름. 이 범주의 이름은 클래스 정의 컨텍스트 내에서 사용되는 경우 기본 클래스와 파생 클래스의 “비공개” 특성 간의 이름 충돌을 방지하기 위해 맹글링된 형식을 사용하도록 다시 작성됩니다. 식별자(이름) 섹션을 참조하십시오.

2.4. Literals

리터럴은 일부 기본 제공 유형의 상수 값에 대한 표기법입니다.

2.4.1. String and Bytes literals

문자열 리터럴은 다음 어휘 정의로 설명됩니다.

stringliteral   ::=  [stringprefix](shortstring | longstring)
stringprefix    ::=  "r" | "u" | "R" | "U" | "f" | "F"
                     | "fr" | "Fr" | "fR" | "FR" | "rf" | "rF" | "Rf" | "RF"
shortstring     ::=  "'" shortstringitem* "'" | '"' shortstringitem* '"'
longstring      ::=  "'''" longstringitem* "'''" | '"""' longstringitem* '"""'
shortstringitem ::=  shortstringchar | stringescapeseq
longstringitem  ::=  longstringchar | stringescapeseq
shortstringchar ::=  <any source character except "\" or newline or the quote>
longstringchar  ::=  <any source character except "\">
stringescapeseq ::=  "\" <any source character>
bytesliteral   ::=  bytesprefix(shortbytes | longbytes)
bytesprefix    ::=  "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"
shortbytes     ::=  "'" shortbytesitem* "'" | '"' shortbytesitem* '"'
longbytes      ::=  "'''" longbytesitem* "'''" | '"""' longbytesitem* '"""'
shortbytesitem ::=  shortbyteschar | bytesescapeseq
longbytesitem  ::=  longbyteschar | bytesescapeseq
shortbyteschar ::=  <any ASCII character except "\" or newline or the quote>
longbyteschar  ::=  <any ASCII character except "\">
bytesescapeseq ::=  "\" <any ASCII character>

이러한 생성에 의해 표시되지 않는 한 가지 구문 제한은 stringprefix 또는 bytesprefix와 나머지 리터럴 사이에 공백이 허용되지 않는다는 것입니다. 소스 문자 집합은 인코딩 선언에 의해 정의됩니다. 소스 파일에 인코딩 선언이 없으면 UTF-8입니다. 인코딩 선언 섹션을 참조하십시오.

일반 영어: 두 유형의 리터럴 모두 일치하는 작은따옴표(‘) 또는 큰따옴표(“)로 묶을 수 있습니다. 세 개의 작은따옴표 또는 큰따옴표로 구성된 일치하는 그룹으로 묶을 수도 있습니다(일반적으로 삼중따옴표 문자열이라고 함). ) 백슬래시() 문자는 개행 문자, 백슬래시 자체 또는 따옴표 문자와 같이 특별한 의미가 있는 문자를 이스케이프하는 데 사용됩니다.

바이트 리터럴에는 항상 ‘b’ 또는 ‘B’ 접두사가 붙습니다. str 유형 대신 바이트 유형의 인스턴스를 생성합니다. ASCII 문자만 포함할 수 있습니다. 숫자 값이 128 이상인 바이트는 이스케이프로 표현해야 합니다.

문자열 및 바이트 리터럴 모두 선택적으로 문자 ‘r’ 또는 ‘R’ 접두사가 붙을 수 있습니다. 이러한 문자열을 원시 문자열이라고 하며 백슬래시를 리터럴 문자로 취급합니다. 결과적으로 문자열 리터럴에서 원시 문자열의 ‘\U’ 및 ‘\u’ 이스케이프는 특별히 처리되지 않습니다. Python 2.x의 원시 유니코드 리터럴이 Python 3.x와 다르게 작동하므로 ‘ur’ 구문은 지원되지 않습니다.

버전 3.3의 새로운 기능: 원시 바이트 리터럴의 ‘rb’ 접두사가 ‘br’의 동의어로 추가되었습니다.

버전 3.3의 새로운 기능: 이중 Python 2.x 및 3.x 코드베이스의 유지 관리를 단순화하기 위해 유니코드 레거시 리터럴(u’value’)에 대한 지원이 다시 도입되었습니다. 자세한 내용은 PEP 414를 참조하십시오.

접두사에 ‘f’ 또는 ‘F’가 있는 문자열 리터럴은 형식이 지정된 문자열 리터럴입니다. 형식화된 문자열 리터럴을 참조하세요. ‘f’는 ‘r’과 결합할 수 있지만 ‘b’ 또는 ‘u’와는 결합할 수 없습니다. 따라서 형식이 지정된 원시 문자열은 가능하지만 형식이 지정된 바이트 리터럴은 불가능합니다.

삼중 따옴표 리터럴에서 이스케이프되지 않은 줄 바꿈과 따옴표가 허용되고 유지됩니다. 단, 이스케이프되지 않은 따옴표 세 개가 연속으로 리터럴을 종료하는 경우는 예외입니다. (“따옴표”는 리터럴을 여는 데 사용되는 문자, 즉 ‘ 또는 “입니다.)

‘r’ 또는 ‘R’ 접두사가 없으면 문자열 및 바이트 리터럴의 이스케이프 시퀀스는 표준 C에서 사용하는 규칙과 유사한 규칙에 따라 해석됩니다. 인식되는 이스케이프 시퀀스는 다음과 같습니다.

Escape SequenceMeaningNotes
\<newline>Backslash and newline ignored(1)
\\Backslash (\)
\'Single quote (')
\"Double quote (")
\aASCII Bell (BEL)
\bASCII Backspace (BS)
\fASCII Formfeed (FF)
\nASCII Linefeed (LF)
\rASCII Carriage Return (CR)
\tASCII Horizontal Tab (TAB)
\vASCII Vertical Tab (VT)
\oooCharacter with octal value ooo(2,4)
\xhhCharacter with hex value hh(3,4)

문자열 리터럴에서만 인식되는 이스케이프 시퀀스는 다음과 같습니다.

Escape SequenceMeaningNotes
\N{name}Character named name in the Unicode database(5)
\uxxxxCharacter with 16-bit hex value xxxx(6)
\UxxxxxxxxCharacter with 32-bit hex value xxxxxxxx(7)

Notes:

1. 새 줄을 무시하기 위해 줄 끝에 백슬래시를 추가할 수 있습니다.

>>> 'This string will not include \
... backslashes or newline characters.'
'This string will not include backslashes or newline characters.'

삼중 인용 문자열이나 괄호 및 문자열 리터럴 연결을 사용하여 동일한 결과를 얻을 수 있습니다.

2. 표준 C에서와 같이 최대 3개의 8진수를 사용할 수 있습니다.

버전 3.11에서 변경: 값이 0o377보다 큰 8진수 이스케이프는 DeprecationWarning을 생성합니다. 향후 Python 버전에서는 SyntaxWarning이 되고 결국에는 SyntaxError가 됩니다.

3. 표준 C와 달리 정확히 두 개의 16진수가 필요합니다.

4. 바이트 리터럴에서 16진수 및 8진수 이스케이프는 주어진 값을 가진 바이트를 나타냅니다. 문자열 리터럴에서 이러한 이스케이프는 주어진 값을 가진 유니코드 문자를 나타냅니다.

5. 버전 3.3에서 변경: 이름 별칭 1에 대한 지원이 추가되었습니다.

6. 정확히 4개의 16진수가 필요합니다.

7. 모든 유니코드 문자는 이 방법으로 인코딩할 수 있습니다. 정확히 8개의 16진수가 필요합니다.

표준 C와 달리 인식되지 않는 모든 이스케이프 시퀀스는 문자열에 변경되지 않은 상태로 남습니다. 즉, 백슬래시가 결과에 남습니다. (이 동작은 디버깅할 때 유용합니다. 이스케이프 시퀀스를 잘못 입력하면 결과 출력이 더 쉽게 깨진 것으로 인식됩니다.) 또한 문자열 리터럴에서만 인식되는 이스케이프 시퀀스가 바이트에 대한 인식되지 않는 이스케이프 범주에 속한다는 점에 유의해야 합니다. 리터럴.

버전 3.6에서 변경: 인식되지 않는 이스케이프 시퀀스는 DeprecationWarning을 생성합니다. 향후 Python 버전에서는 SyntaxWarning이 되고 결국에는 SyntaxError가 됩니다.

원시 리터럴에서도 따옴표는 백슬래시로 이스케이프할 수 있지만 백슬래시는 결과에 남아 있습니다. 예를 들어 r”\””는 백슬래시와 큰따옴표의 두 문자로 구성된 유효한 문자열 리터럴이고 r”\”는 유효한 문자열 리터럴이 아닙니다(원시 문자열도 홀수 백슬래시로 끝날 수 없음). 특히, 원시 리터럴은 단일 백슬래시로 끝날 수 없습니다(백슬래시가 다음 인용 문자를 이스케이프하기 때문입니다. 또한 단일 백슬래시 뒤에 줄 바꿈이 있는 경우 이 두 문자는 줄 연속이 아니라 리터럴의 일부로 해석됩니다. .

2.4.2. String literal concatenation

서로 다른 인용 규칙을 사용하는 여러 인접 문자열 또는 바이트 리터럴(공백으로 구분)이 허용되며 해당 의미는 연결과 동일합니다. 따라서 “hello” ‘world’는 “helloworld”와 동일합니다. 이 기능을 사용하여 필요한 백슬래시 수를 줄이고 긴 문자열을 여러 줄로 편리하게 분할하거나 문자열의 일부에 주석을 추가할 수도 있습니다. 예를 들면 다음과 같습니다.

re.compile("[A-Za-z_]"       # letter or underscore
           "[A-Za-z0-9_]*"   # letter, digit or underscore
          )

이 기능은 구문 수준에서 정의되지만 컴파일 타임에 구현됩니다. 런타임에 문자열 식을 연결하려면 ‘+’ 연산자를 사용해야 합니다. 또한 리터럴 연결은 각 구성 요소에 대해 서로 다른 인용 스타일을 사용할 수 있으며(심지어 원시 문자열과 삼중 인용 문자열을 혼합하는 경우도 있음) 형식이 지정된 문자열 리터럴은 일반 문자열 리터럴과 연결할 수 있습니다.

2.4.3. Formatted string literals

버전 3.6의 새로운 기능.

형식이 지정된 문자열 리터럴 또는 f-string은 ‘f’ 또는 ‘F’ 접두사가 붙는 문자열 리터럴입니다. 이러한 문자열에는 중괄호 {}로 구분된 표현식인 대체 필드가 포함될 수 있습니다. 다른 문자열 리터럴은 항상 상수 값을 갖지만 형식이 지정된 문자열은 실제로 런타임에 평가되는 표현식입니다.

이스케이프 시퀀스는 일반 문자열 리터럴과 같이 디코딩됩니다(리터럴이 원시 문자열로도 표시되는 경우 제외). 디코딩 후 문자열 내용의 문법은 다음과 같습니다.

f_string          ::=  (literal_char | "{{" | "}}" | replacement_field)*
replacement_field ::=  "{" f_expression ["="] ["!" conversion] [":" format_spec] "}"
f_expression      ::=  (conditional_expression | "*" or_expr)
                         ("," conditional_expression | "," "*" or_expr)* [","]
                       | yield_expression
conversion        ::=  "s" | "r" | "a"
format_spec       ::=  (literal_char | NULL | replacement_field)*
literal_char      ::=  <any code point except "{", "}" or NULL>

이중 중괄호 ‘{{‘ 또는 ‘}}’가 해당하는 단일 중괄호로 대체되는 것을 제외하고 중괄호 외부의 문자열 부분은 문자 그대로 처리됩니다. 단일 여는 중괄호 ‘{‘는 Python 식으로 시작하는 대체 필드를 표시합니다. 평가 후 식 텍스트와 해당 값을 모두 표시하려면(디버깅에 유용함) 식 뒤에 등호 ‘=’를 추가할 수 있습니다. 느낌표 ‘!’로 시작되는 변환 필드 따를 수 있습니다. 콜론 ‘:’으로 시작하는 형식 지정자를 추가할 수도 있습니다. 대체 필드는 닫는 중괄호 ‘}’로 끝납니다.

형식이 지정된 문자열 리터럴의 식은 몇 가지 예외를 제외하고 괄호로 묶인 일반 Python 식처럼 처리됩니다. 빈 식은 허용되지 않으며 람다 식과 대입 식 := 모두 명시적 괄호로 묶어야 합니다. 대체 표현식은 줄 바꿈(예: 삼중 인용 문자열)을 포함할 수 있지만 주석은 포함할 수 없습니다. 각 식은 형식이 지정된 문자열 리터럴이 나타나는 컨텍스트에서 왼쪽에서 오른쪽 순서로 평가됩니다.

버전 3.7에서 변경: Python 3.7 이전에는 async for 절을 포함하는 await 표현식 및 이해가 구현 문제로 인해 형식이 지정된 문자열 리터럴의 표현식에서 불법이었습니다.

등호 ‘=’가 제공되면 출력에 표현식 텍스트, ‘=’ 및 평가된 값이 포함됩니다. 여는 중괄호 ‘{‘ 뒤, 식 내 및 ‘=’ 뒤의 공백은 모두 출력에 유지됩니다. 기본적으로 ‘=’는 지정된 형식이 없는 한 표현식의 repr()이 제공되도록 합니다. 형식이 지정되면 변환 ‘!r’이 선언되지 않는 한 기본적으로 표현식의 str()이 됩니다.

버전 3.8의 새로운 기능: 등호 ‘=’.

변환이 지정된 경우 식을 평가한 결과는 서식을 지정하기 전에 변환됩니다. 변환 ‘!s’는 결과에 대해 str()을 호출하고, ‘!r’은 repr()을 호출하고, ‘!a’는 ascii()를 호출합니다.

그런 다음 결과는 format() 프로토콜을 사용하여 형식화됩니다. 형식 지정자는 표현식 또는 변환 결과의 format() 메서드에 전달됩니다. 형식 지정자가 생략되면 빈 문자열이 전달됩니다. 형식화된 결과는 전체 문자열의 최종 값에 포함됩니다.

최상위 형식 지정자는 중첩된 대체 필드를 포함할 수 있습니다. 이러한 중첩 필드에는 자체 변환 필드 및 형식 지정자가 포함될 수 있지만 더 깊이 중첩된 대체 필드는 포함되지 않을 수 있습니다. 형식 지정자 미니 언어는 str.format() 메서드에서 사용하는 것과 동일합니다.

형식이 지정된 문자열 리터럴은 연결할 수 있지만 대체 필드는 리터럴 간에 분할할 수 없습니다.

형식이 지정된 문자열 리터럴의 몇 가지 예:

>>> name = "Fred"
>>> f"He said his name is {name!r}."
"He said his name is 'Fred'."
>>> f"He said his name is {repr(name)}."  # repr() is equivalent to !r
"He said his name is 'Fred'."
>>> width = 10
>>> precision = 4
>>> value = decimal.Decimal("12.34567")
>>> f"result: {value:{width}.{precision}}"  # nested fields
'result:      12.35'
>>> today = datetime(year=2017, month=1, day=27)
>>> f"{today:%B %d, %Y}"  # using date format specifier
'January 27, 2017'
>>> f"{today=:%B %d, %Y}" # using date format specifier and debugging
'today=January 27, 2017'
>>> number = 1024
>>> f"{number:#0x}"  # using integer format specifier
'0x400'
>>> foo = "bar"
>>> f"{ foo = }" # preserves whitespace
" foo = 'bar'"
>>> line = "The mill's closed"
>>> f"{line = }"
'line = "The mill\'s closed"'
>>> f"{line = :20}"
"line = The mill's closed   "
>>> f"{line = !r:20}"
'line = "The mill\'s closed" '

일반 문자열 리터럴과 동일한 구문을 공유한 결과 대체 필드의 문자가 외부 형식 문자열 리터럴에 사용된 인용부호와 충돌하지 않아야 합니다.

f"abc {a["x"]} def"    # error: outer string literal ended prematurely
f"abc {a['x']} def"    # workaround: use different quoting

형식 표현식에는 백슬래시가 허용되지 않으며 오류가 발생합니다.

f"newline: {ord('\n')}"  # raises SyntaxError

백슬래시 이스케이프가 필요한 값을 포함하려면 임시 변수를 만듭니다.

>>> newline = ord('\n')
>>> f"newline: {newline}"
'newline: 10'

형식이 지정된 문자열 리터럴은 표현식을 포함하지 않더라도 독스트링으로 사용할 수 없습니다.

def foo():
    f"Not a docstring"

foo.__doc__ is None
True

또한 형식화된 문자열 리터럴을 추가한 제안에 대해서는 PEP 498과 관련 형식 문자열 메커니즘을 사용하는 str.format()을 참조하십시오.

2.4.4. Numeric literals

숫자 리터럴에는 정수, 부동 소수점 숫자 및 허수의 세 가지 유형이 있습니다. 복소수 리터럴이 없습니다(복소수는 실수와 허수를 더하여 형성할 수 있음).

숫자 리터럴에는 기호가 포함되지 않습니다. -1과 같은 구문은 실제로 단항 연산자 ‘-‘와 리터럴 1로 구성된 표현식입니다.

2.4.5. Integer literals

정수 리터럴은 다음 어휘 정의로 설명됩니다.

integer      ::=  decinteger | bininteger | octinteger | hexinteger
decinteger   ::=  nonzerodigit (["_"] digit)* | "0"+ (["_"] "0")*
bininteger   ::=  "0" ("b" | "B") (["_"] bindigit)+
octinteger   ::=  "0" ("o" | "O") (["_"] octdigit)+
hexinteger   ::=  "0" ("x" | "X") (["_"] hexdigit)+
nonzerodigit ::=  "1"..."9"
digit        ::=  "0"..."9"
bindigit     ::=  "0" | "1"
octdigit     ::=  "0"..."7"
hexdigit     ::=  digit | "a"..."f" | "A"..."F"

사용 가능한 메모리에 저장할 수 있는 것 외에 정수 리터럴의 길이에는 제한이 없습니다.

리터럴의 숫자 값을 결정할 때 밑줄은 무시됩니다. 가독성을 높이기 위해 숫자를 그룹화하는 데 사용할 수 있습니다. 하나의 밑줄은 숫자 사이와 0x와 같은 기본 지정자 뒤에 나타날 수 있습니다.

0이 아닌 십진수 앞에 오는 0은 허용되지 않습니다. 이것은 Python이 버전 3.0 이전에 사용했던 C 스타일의 8진수 리터럴을 명확하게 하기 위한 것입니다.

정수 리터럴의 몇 가지 예:

7     2147483647                        0o177    0b100110111
3     79228162514264337593543950336     0o377    0xdeadbeef
      100_000_000_000                   0b_1110_0101

버전 3.6에서 변경: 이제 리터럴에서 그룹화 목적으로 밑줄이 허용됩니다.

2.4.6. Floating point literals

부동 소수점 리터럴은 다음 어휘 정의로 설명됩니다.

floatnumber   ::=  pointfloat | exponentfloat
pointfloat    ::=  [digitpart] fraction | digitpart "."
exponentfloat ::=  (digitpart | pointfloat) exponent
digitpart     ::=  digit (["_"] digit)*
fraction      ::=  "." digitpart
exponent      ::=  ("e" | "E") ["+" | "-"] digitpart

정수 및 지수 부분은 항상 기수 10을 사용하여 해석됩니다. 예를 들어 077e010은 유효하며 77e10과 같은 숫자를 나타냅니다. 부동 소수점 리터럴의 허용 범위는 구현에 따라 다릅니다. 정수 리터럴에서와 같이 숫자 그룹화에 밑줄이 지원됩니다.

부동 소수점 리터럴의 몇 가지 예:

3.14    10.    .001    1e100    3.14e-10    0e0    3.14_15_93

버전 3.6에서 변경: 이제 리터럴에서 그룹화 목적으로 밑줄이 허용됩니다.

2.4.7. Imaginary literals

가상 리터럴은 다음 어휘 정의로 설명됩니다.

imagnumber ::=  (floatnumber | digitpart) ("j" | "J")

허수 리터럴은 실수부가 0.0인 복소수를 생성합니다. 복소수는 한 쌍의 부동 소수점 숫자로 표현되며 범위에 동일한 제한이 있습니다. 0이 아닌 실수 부분으로 복소수를 생성하려면 여기에 부동 소수점 숫자를 추가합니다(예: (3+4j)). 가상 리터럴의 몇 가지 예:

3.14j   10.j    10j     .001j   1e100j   3.14e-10j   3.14_15_93j

2.5. Operators

다음 토큰은 연산자입니다.

+       -       *       **      /       //      %      @
<<      >>      &       |       ^       ~       :=
<       >       <=      >=      ==      !=

2.6. Delimiters

다음 토큰은 문법에서 구분 기호 역할을 합니다.

(       )       [       ]       {       }
,       :       .       ;       @       =       ->
+=      -=      *=      /=      //=     %=      @=
&=      |=      ^=      >>=     <<=     **=

마침표는 부동 소수점 및 가상 리터럴에서도 발생할 수 있습니다. 세 마침표의 시퀀스는 줄임표 리터럴로서 특별한 의미를 갖습니다. 목록의 후반부인 증분 할당 연산자는 어휘적으로 구분 기호 역할을 하지만 연산도 수행합니다.

다음 인쇄 ASCII 문자는 다른 토큰의 일부로 특별한 의미를 갖거나 어휘 분석기에 중요합니다.

'       "       #       \

다음 인쇄 ASCII 문자는 Python에서 사용되지 않습니다. 문자열 리터럴 및 주석 외부에서 발생하는 것은 무조건 오류입니다.

$       ?       `

Source: https://docs.python.org/3/reference/lexical_analysis.html

Python Language Reference > 1. Introduction

이 참조 설명서는 Python 프로그래밍 언어에 대해 설명합니다. 튜토리얼이 아닙니다.

가능한 한 정확하게 하려고 노력하면서 구문과 어휘 분석을 제외한 모든 것에 형식적인 사양보다는 영어를 사용하기로 했습니다. 이렇게 하면 일반 독자가 문서를 더 쉽게 이해할 수 있지만 모호할 여지가 있습니다. 결과적으로, 만약 당신이 Mars 출신이고 이 문서만으로 Python을 다시 구현하려고 시도했다면, 추측해야 할 수도 있고 사실 꽤 다른 언어를 구현하게 될 것입니다. 반면에 Python을 사용하고 있고 언어의 특정 영역에 대한 정확한 규칙이 무엇인지 궁금하다면 여기에서 확실히 찾을 수 있을 것입니다. 언어에 대한 보다 공식적인 정의를 보고 싶다면 자원봉사를 하거나 복제 기계를 발명할 수 있습니다 :-).

언어 참조 문서에 너무 많은 구현 세부 정보를 추가하는 것은 위험합니다. 구현이 변경될 수 있고 동일한 언어의 다른 구현이 다르게 작동할 수 있습니다. 반면에 CPython은 널리 사용되는 Python 구현 중 하나이며(대체 구현이 계속 지원되고 있음) 특히 구현이 추가 제한을 부과하는 경우 특정 단점을 언급할 가치가 있습니다. 따라서 텍스트 전체에 걸쳐 짧은 “구현 참고 사항”이 표시됩니다.

모든 Python 구현에는 여러 내장 및 표준 모듈이 함께 제공됩니다. 이들은 Python 표준 라이브러리에 문서화되어 있습니다. 몇 가지 기본 제공 모듈은 언어 정의와 중요한 방식으로 상호 작용할 때 언급됩니다.

1.1. Alternate Implementations

지금까지 가장 인기 있는 Python 구현이 하나 있지만, 다른 청중이 특히 관심을 갖는 몇 가지 대체 구현이 있습니다.

알려진 구현은 다음과 같습니다.

C파이썬
이것은 C로 작성된 Python의 원본이자 가장 유지 관리된 구현입니다. 일반적으로 새로운 언어 기능이 여기에 먼저 나타납니다.

자이썬
자바로 구현된 파이썬. 이 구현은 Java 응용 프로그램용 스크립팅 언어로 사용하거나 Java 클래스 라이브러리를 사용하여 응용 프로그램을 만드는 데 사용할 수 있습니다. 또한 Java 라이브러리에 대한 테스트를 만드는 데 자주 사용됩니다. 자세한 내용은 Jython 웹사이트에서 확인할 수 있습니다.

.NET용 파이썬
이 구현은 실제로 CPython 구현을 사용하지만 관리되는 .NET 애플리케이션이며 .NET 라이브러리를 사용할 수 있게 합니다. Brian Lloyd가 만들었습니다. 자세한 내용은 Python for .NET 홈 페이지를 참조하세요.

철파이썬
.NET용 대체 Python입니다. Python.NET과 달리 IL을 생성하고 Python 코드를 .NET 어셈블리로 직접 컴파일하는 완전한 Python 구현입니다. Jython의 창시자인 Jim Hugunin이 만들었습니다. 자세한 내용은 IronPython 웹 사이트를 참조하십시오.

파이파이
Python으로 완전히 작성된 Python 구현입니다. 스택리스 지원 및 Just in Time 컴파일러와 같은 다른 구현에서는 볼 수 없는 몇 가지 고급 기능을 지원합니다. 이 프로젝트의 목표 중 하나는 인터프리터(Python으로 작성되었으므로)를 더 쉽게 수정할 수 있도록 하여 언어 자체에 대한 실험을 장려하는 것입니다. 추가 정보는 PyPy 프로젝트의 홈페이지에서 확인할 수 있습니다.

이러한 각각의 구현은 이 설명서에 설명된 언어와 어떤 식으로든 다르거나 표준 Python 설명서에서 다루는 것 이상의 특정 정보를 소개합니다. 사용 중인 특정 구현에 대해 알아야 할 기타 사항을 확인하려면 구현 관련 문서를 참조하세요.

1.2. Notation

어휘 분석 및 구문 설명은 수정된 BNF 문법 표기법을 사용합니다. 이것은 다음 정의 스타일을 사용합니다.

name      ::=  lc_letter (lc_letter | "_")*
lc_letter ::=  "a"..."z"

첫 번째 줄은 이름이 lc_letter이고 그 뒤에 0개 이상의 lc_letter와 밑줄이 오는 순서임을 나타냅니다. lc_letter는 ‘a’부터 ‘z’까지의 단일 문자 중 하나입니다. (이 규칙은 이 문서의 어휘 및 문법 규칙에 정의된 이름에 대해 실제로 준수됩니다.)

각 규칙은 이름(규칙에 의해 정의된 이름)과 ::=로 시작합니다. 세로 막대(|)는 대안을 구분하는 데 사용됩니다. 이 표기법에서 가장 구속력이 적은 연산자입니다. 별표(*)는 이전 항목이 0회 이상 반복되었음을 의미합니다. 마찬가지로 더하기(+)는 하나 이상의 반복을 의미하고 대괄호([ ])로 묶인 구는 0개 또는 1개의 발생을 의미합니다(즉, 동봉된 구는 선택 사항임). * 및 + 연산자는 최대한 긴밀하게 바인딩합니다. 괄호는 그룹화에 사용됩니다. 리터럴 문자열은 따옴표로 묶습니다. 공백은 토큰을 구분할 때만 의미가 있습니다. 규칙은 일반적으로 한 줄에 포함됩니다. 대안이 많은 규칙은 수직 막대로 시작하는 첫 번째 줄 다음에 각 줄로 번갈아 서식을 지정할 수 있습니다.

어휘 정의(위의 예)에서 두 가지 규칙이 더 사용됩니다. 세 개의 점으로 구분된 두 개의 리터럴 문자는 주어진(포함) ASCII 문자 범위에서 단일 문자의 선택을 의미합니다. 각괄호(<…>) 사이의 구는 정의된 기호에 대한 비공식 설명을 제공합니다. 예를 들어, 필요한 경우 ‘제어 문자’의 개념을 설명하는 데 사용할 수 있습니다.

사용된 표기법은 거의 동일하지만 어휘 정의와 구문 정의 사이에는 큰 차이가 있습니다. 어휘 정의는 입력 소스의 개별 문자에서 작동하는 반면 구문 정의는 입력 소스에서 생성된 토큰 스트림에서 작동합니다. 어휘 분석. 다음 장(“어휘 분석”)에서 BNF의 모든 사용은 어휘 정의입니다. 후속 장에서 사용되는 것은 구문 정의입니다.

Source:https://docs.python.org/3/reference/introduction.html

Colon in Python

이번시간에는 파이썬 배열의 :를 활용하는 방법에 대해 공부해볼게요.

배열에서의 콜론

# 5개의 정수가 들어있는 배열을 하나 선언합니다
>>> example = [1, 2, 3, 4, 5]

# 2번째 인덱스 오른쪽의 모든 아이템을 가져와라
>>> example[2:]
[3, 4, 5]

# 2번째 인덱스 왼쪽의 모든 아이템을 가져와라
>>> example[:2]
[1, 2]

# 2부터 4까지의 아이템을 가져와라
>>> example[2:4]
[3, 4]

# 2부터 4까지 아이템 바꿔치기
>>> example[2:4] = [10, 11]
>>> example
[1, 2, 10, 11, 5]

이차원 배열에서는 다음과 같이 활용할수 있습니다. 우선 numpy라이브러리를 사용하기 위해서 현재 python버젼에 numpy를 설치해줄게요.

> pip install numpy
# numpy를 사용하기 위해서 라이브러리를 추가하고
>>> import numpy as np

# 0부터 39까지 아이템을 가진 배열을 하나 만듭니다.
>>> arr2d = np.arange(0,40)
>>> arr2d
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39])

# 해당 배열을 5개행, 8개열로 나눠서 이차원 배열로 만듭니다. 
>>> arr2d = arr2d.reshape([5, 8])
>>> arr2d
array([[ 0,  1,  2,  3,  4,  5,  6,  7],
       [ 8,  9, 10, 11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29, 30, 31],
       [32, 33, 34, 35, 36, 37, 38, 39]])

# 첫번째 행의 모든 원소를 가져와라
>>> arr2d[0, :]
array([0, 1, 2, 3, 4, 5, 6, 7])

# 첫번째 열의 모든 원소를 가져와라
>>> arr2d[: ,0]
array([ 0,  8, 16, 24, 32])

위의 예제에서 보시는 바와 같이 배열에서 :는 모든 원소를 의미하며, 앞이나 뒤에 숫자가 붙으면 반환할 원소들의 시작 주소로 인식하게 됩니다.

문자열에서 콜론

문자열에서 :은 문자열을 쪼개는데 사용됩니다.

>>> a = "AskPython"
>>> print(a[2:8])
kPytho

>>> a = "AskPython"
>>> print(a[3:])
Python

>>> a = "AskPython"
>>> print(a[:7])
AskPyth

>>> a = "AskPython"
>>> print(a[-5:-2])
yth

Double Colon ::

더블콜론은 콜론과 마찬가지로 문자열이나 배열을 쪼갤때 사용되는데 추가로 아이템들을 건너뛰면서 쪼갤수 있습니다.

>>> string = "Ask Python"[5::]
>>> print(string)
ython

>>> string = "What's up AskPython"[0:19:2]
>>> print(string)
Wa' pAkyhn

>>> string="What's up AskPython"[::2]
>>> print(string)
Wa' pAkyhn

위의 예시에서 보는 바와같이 더블콜론은 [Start : Stop : Steps]의 형식을 가집니다.

Colon in Assignment Expressions

The Walrus :=

할당기호(:=)가 바다코끼리를 닮았다고 해서 바다코끼리라고도 불리우는 이 operator는 계산도중 값을 저장하고 싶을때 주로 사용됩니다. 예를 들면 아래의 코드처럼 numbers라는 배열을 돌면서 해당 값이 slow함수를 거쳤을때 0보다 큰 경우 slow함수의 결과를 반환하도록 합니다.

numbers = [7, 6, 1, 4, 1, 8, 0, 6]
results = [slow(num) for num in numbers if slow(num) > 0]

이때, 반환시에 slow함수를 한번더 호출하는 것보다 조건을 비교할때 value라는 변수에 저장을 해두었다가 해당 변수를 반환하면 slow함수를 두번 호출하는 번거로움을 줄일수 있어서 더 효율적입니다.

results = [value for num in numbers if (value := slow(num)) > 0]

물론 위의 코드를 옛날방식으로 바꿔서 for문에 넣고 기존 할당기능를 이용해서 아래와 같이 구현할수도 있습니다.

results = []
for num in numbers:
    value = slow(num)
    if value > 0:
        results.append(value)

하지만 이 방법은 코드를 읽어야만 기존리스트를 이용해서 새로운 리스트를 만든다는 것을 알수 있는 반면, 위의 코드는 간결하게 한눈에 기존 리스트를 변환하여 새로운 리스트를 만든다는 그 의도를 한눈에 파악할수 있습니다.

BNF (Backus–Naur Form) notation ::=

가끔 파이썬 코드를 보다보면 ::=를 사용한 예제가 있습니다. ::=:=와 같은 기능을 하지만 :=는 파이썬의 문법인 반면, ::=는 BNF라는 표기법의 형식입니다. BNF는 언어에 관계없이 널리 사용되고 있는 표기법이며, 이 표기법을 파이썬에서도 지원하고 있습니다. 이렇게 언어에 관계없이 사용되어지는 문법표현들을 모아서 metasyntax라고 부릅니다.

Connect MySQL in Python

pip install mysql-connector-python
import mysql.connector
from mysql.connector import Error

try:
    connection = mysql.connector.connect(host='localhost',
                                         database='test',
                                         user='test',
                                         password='test')
    if connection.is_connected():
        db_Info = connection.get_server_info()
        print("Connected to MySQL Server version ", db_Info)
        cursor = connection.cursor()
        cursor.execute("select database();")
        record = cursor.fetchone()
        print("You're connected to database: ", record)

except Error as e:
    print("Error while connecting to MySQL", e)
finally:
    if connection.is_connected():
        cursor.close()
        connection.close()
        print("MySQL connection is closed")

React in 30 minutes

참고로, 이 문서는 2022년 9월13일 기준으로 작성되었습니다. Frontend 기술은 하루가 다르게 변하기 때문에 당신이 이 문서를 보는 시점이 1년이 지난 시점이라면 여기에서 실행하는 코드중에 실행이 안되는 코드가 있을수 있다는점 알려드립니다.

React를 시작하려면 컴퓨터에 node가 설치가 되어있어야합니다. node가 설치가 되지 않았다면 여기를 누르시고 node를 설치한 뒤에 다시 와서 계속해주세요.

node가 정상적으로 설치가 되었다면 npx가 함께 설치가 되었을겁니다. 프로젝트를 진행할 폴더를 새로 하나 만드시고 그 안에 들어가셔서 npx create-react-app .명령을 실행해주세요. 저는 폴더명을 todolist라고 했습니다. TODO리스트를 관리하는 프로그램을 만들거거든요.

$ cd todolist
$ npx create-react-app .
...
Success! Created my_react_project at /Users/me/todolist
Inside that directory, you can run several commands:
  npm start
    Starts the development server.

  npm run build
    Bundles the app into static files for production.

  npm test
    Starts the test runner.

  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!

We suggest that you begin by typing:

  cd /Users/me/todolist
  npm start

한참을 설치한 뒤에 위와 같이 성공적으로 프로젝트가 생성되었다는 메세지가 뜨고, 이하 실행가능한 npm 명령어들을 보여줍니다.

  • npm start: 애플리케이션을 시작하는 명령어로써 웹서버를 실행합니다.
  • npm run build: 수정된 파일들을 실서버에 적용하는 명령어
  • npm test: 선행 정의된 각종 테스트를 실행하는 명령어
  • npm run eject: 프로젝트에 숨겨져있는 모든 설정을 밖으로 추출하는 명령인데 이를 통해 webpack과 babel의 자유로운 세팅이 가능하게 됩니다. 단, 이 명령은 한번 실행하면 되돌리기 힘들기때문에 반드시 정확하게 이해한 후에 실행하시기 바랍니다.

프로젝트를 생성하신 뒤 폴더를 보시면 옆의 구조로 파일들이 자동으로 생성되어있는 것을 확인 하실 수 있으세요. 클라이언트가 웹사이트에 접속하게 되면 가장 먼저 실행되는 파일이 바로 index.js입니다. index.js를 열어보시면 상수 root에 ReactDOM.createRoot(document.getElementById('root')) root라는 ID를 가진 HTML객체를 가져와서 ReactDOM으로 문서를 생성합니다. 그리고 그 객체 안에 내용을 넣도록 root.render 함수를 호출 하는데요. 그때 인자로 들어가는 태그의 이름이 아래코드에서 보시는 것과 같이 App이라고 명시되어 있습니다. App이라는 컴포넌트를 가져다가 화면에 출력해주겠다는 뜻입니다.

root.render(
    <App />
);

App이라는 컴포넌트는 바로 App.js에 정의된 App이라는 이름으로 공유된 함수의 결과입니다. App.js에 들어가보시면 App()함수에서 화면에 보여줄 코드를 반환하고 있고, 이 함수를 맨 아래 export default App명령을 통해서 외부에서 접속할수 있게 제공합니다.

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

위의 코드가 제대로 실행이 되는지 서버를 한번 띄워보도록 하겠습니다. 아래 명령을 실행할때에는 반드시 해당 프로젝트 폴더에 들어가신 후 실행 하셔야합니다.

$ npm start

위의 명령어를 실행하면 브라우저창이 자동으로 뜨면서 http://localhost:3000/를 로딩합니다.

위의 이미지가 나오면 서버가 성공적으로 실행이 된 것입니다.

현재 보이는 디자인은 React가 default로 보여주는건데 우리가 만들 프로젝트에서는 이게 필요없으니까 App함수에서 null을 반환하도록 변경해볼게요. 그리고 App.css와 react logo 파일도 import할 필요 없으니까 지울게요.

function App() {
  return null
}

export default App;

저장과 동시에 브라우저의 웹화면이 백지화 되는 것을 보실수 있으실겁니다.

Component

자 그럼 이제, 새로운 컴포넌트를 하나 만들어 볼까요? 일단 현재 TODO리스트를 화면에 보여주는 걸 한번 구현해 볼게요. 코드를 App에 바로 구현하는것 보다 TODO리스트를 모듈화 해서 다른 파일에 컴포넌트로 구현해서 여기서 불러다 쓰면 코드가 더 깔끔할것 같으니 일단 여기서는 TodoList라는 컴포넌트를 불러다가 출력해주는걸로 합니다. 이렇게 하면 index.js가 App을 호출하고 App은 TodoList를 호출하여 결과적으로 화면에 출력해주게 되는 거죠.

function App() {
  return (
    <TodoList />
  );
}

<TodoList />는 생긴게 마치 HTML 태그같기도 하지만 그건 아니고 react에서 제공하는 컴포넌트를 호출하는 형식입니다. 아직 TodoList라는 컴포넌트는 만들지 않았지만 앞으로 만들 TodoList를 여기에 넣겠다고 선언한거에요. 그럼 이제 TodoList컴포넌트를 만들어 볼게요. App.js와 같은 폴더에 TodoList.js라는 파일을 생성해주세요. 그리고 아래와 같이 함수를 하나 선언해서 export해주세요.

export default function TodoList() {
	return (
		<div>
		
		</div>
	)
}

그리고 다시 App.js로 돌아가서 우리가 방금 만든 컴포넌트를 import해주세요.

import TodoList from './TodoList'

function App() {
  return (
    <TodoList />
  );
}

export default App;

이렇게 하면 우리가 만든 TodoList를 App이 반환하는 결과 안에 넣게 됩니다. 결과가 잘 들어가는지 TodoList를 한번 수정해 볼까요? TodoList의 결과값에 Hello World를 넣어보면 브라우저 화면에 Hello World가 출력됩니다.

export default function TodoList() {
	return (
		<div>
                     Hello World
		</div>
	)
}

Pass the Variables between Components

Todo리스트를 보여주려면 Todo리스트를 저장할 배열이 있어야겠지요? App()안에 todos라는 배열을 하나 선언해줍니다. 그리고 그 안에 할 일 두개를 저장해볼게요. 그리고 그 배열, todos를 TodoList컴포넌트에 전달해줍니다. todos라고 같은 이름으로 전달하는게 덜 헷갈리겠죠.

function App() {
  const todos = ['Todo 1', 'Todo 2']

  return (
    <TodoList todos={todos}/>
  );
}

그럼 이젠 TodoList에서 배열을 전달 받아야겠죠? 함수의 인자로 todos를 아래와 같이 넣어서 받습니다. 그리고 전달 받은 배열을 화면에 하나씩 돌아가면서 출력해줄건데 이때 배열의 기본 함수인 map()을 이용해서 배열 속 아이템 하나씩 돌면서 화면에 출력을 해주도록 합니다. 브라우저에 Todo 1과 Todo 2가 보이시나요?

export default function TodoList({ todos }) {
	return (
		todos.map(todo => {
			return <div key={todo}>{todo}</div>
		})
	)
}

Todo Item

이제는 사용자한테서 Todo리스트를 하나씩 입력받아서 등록하도록 할건데요. 입력상자는 Todo리스트의 맨 끝에 넣도록 하겠습니다. TodoList컴포넌트를 삽입한 바로 다음에 입력상자와 추가버튼을 아래와 같이 넣도록 하겠습니다.

function App() {
  const todos = ['Todo 1', 'Todo 2']

  return (
    <>
      <TodoList todos={todos}/>
      <input type="text" />
      <button >Add Todo</button>
      <div>0 left to do</div>
    </>
  );
}

위의 코드에서 자세히 보시면요. 결과값 처음과 끝에 빈 태그를 넣어주었어요. 그 이유는 컴포넌트를 반환할때는 반드시 닫는 태그로 끝나야 하기 때문이죠. 아까 TodoList태그 하나만 있을때는 혼자 열고 혼자 닫기 때문에 상관이 없는데 태그가 여러개 추가되면서 닫히지 않은 태그로 인식이 되기때문에 처음과 끝에 의미없는 태그를 넣어서 마무리가 잘 된 상태의 코드를 넘겨주는 거죠. 사실 저 빈 태그는 <React.Fragment>의 약칭입니다.

useRef and handleAddTodo

사용자에게서 Todo아이템을 입력받기 위해서는 사용자가 텍스트상자에 입력한 내용을 읽어와야합니다. 이때 유용하게 사용할수 있는 react함수가 바로 useRef입니다. useRef는 react라이브러리에서 제공하는 기본 함수지만 사용하기 위해서는 반드시 명시를 해주셔야합니다. App.js의 맨 위에 아래와 같이 useRef를 import해주세요. 그리고 App()안에 todoNameRef이름의 상수를 하나 선언하고 해당 함수를 할당합니다. 그리고 아까 추가했던 입력상자의 ref attribute에 todoNameRef를 asstign합니다. 이렇게 하면 입력상자를 todoNameRef라는 이름으로 간편하게 불러서 사용할수 있습니다.

import { useRef } from 'react'
...
function App() {
  const todoNameRef = useRef()
...
   <input ref={todoNameRef} type="text" />

이번에는 버튼을 클릭하면 호출해서 입력받은 Todo아이템을 처리할 함수를 선언하도록 하겠습니다. App()안에 handleAddTodo라는 함수를 하나 선언하고 e를 인자로 받도록 합니다. 그리고 아까 정의한 todoNameRef의 값을 가져와서 name이라는 상수에 저장합니다. 그리고 버튼의 onClick 속성에 방금 정의한 handleAddTodo라는 함수를 아래와 같이 할당합니다.

function App() {
...
  function handleAddTodo(e) {
    const name = todoNameRef.current.value
  }
...
  <button onClick={handleAddTodo}>Add Todo</button>

useState

이제 사용자가 Todo아이템을 입력하면 todos라는 배열에 추가해서 화면에 보여주는 걸 해보겠습니다. 아까는 todos라는 배열을 임의로 선언했는데 사용자가 새로운 아이템을 입력할때마다 수동으로 배열에 값을 추가할수도 있지만 react에는 자주 변경되는 아이템을 깔끔하게 관리할수 있도록 useState라는 모듈을 제공하고 있습니다. 이 모듈은 로컬에 저장공간을 확보하고 해당 저장공간에 정보를 담는일을 손쉽게 할수 있도록 해줍니다. 사용방법은 일단 react라이브러리에서 useState를 import하고 기존에 임의로 선언했던 todos와 두개의 Todo아이템 대신에 useState함수를 호출하여 아래와 같이 값을 받아옵니다. useState에 인자로 들어가는 값은 저장공간의 초기값으로 우리는 빈배열을 넘겨주어 앞으로 이 공간에 배열이 들어가게 될것임을 알립니다. 그리고 useState이 반환하는 결과값은 배열 안에 두개의 값을 넣어서 반환하는데 0번방의 값은 현재 저장 공간에 저장되어 있는 변수의 포인터이고, 1번방에는 해당 저장공간에 저장을 할수 있게 해주는 함수의 포인터를 반환합니다. 우리는 이 함수를 setTodos라는 이름으로 받아서 사용하도록 하겠습니다. 그리고 handleAddTodo에서 입력받은 Todo아이템을 useState를 통해 제공받은 setTodos를 통해서 배열에 추가를 합니다. 아래 코드를 보시면 setTodos를 호출하면서 기존 배열, prevTodos에 새로운 아이템 name을 추가하고 있는 모습을 보실수 있습니다. ...문법에 대해 생소하신 분들은 자바스크립트에서 점 3개(…) 활용법을 참조해주세요. prevTodos는 setTodos를 호출하면 제공받게 되는 기존 저장공간의 포인터입니다. 인자로 함수를 넘겨주고 함수가 실행된 결과를 제공받는 컨셉이 생소하신 분들은 Understanding Array.map()을 한번 읽어보세요. 이런 형식의 함수들을 이해하는데 도움이 되실겁니다. 그리고 배열방에 추가를 한 뒤에 화면에 보이는 입력창은 null로 비워줄게요.

import { useState, useRef } from 'react'
...
function App() {
  const [todos, setTodos] = useState([])
...
  function handleAddTodo(e) {
    const name = todoNameRef.current.value
    if (name === '') return
    setTodos(prevTodos => {
      return [...prevTodos, name]
    })
    todoNameRef.current.value = null
  }

브라우저창을 열고 텍스트상자에 Todo아이템을 입력한뒤 “Add Todo”버튼을 눌보세요. 할일 목록에 하나씩 추가되는게 확인이 되시면 다음으로 넘어갑니다. 혹시 오류가 나는 분들을 위해서 지금까지의 코드를 정리해드릴게요.

App.js

import { useState, useRef, useEffect } from 'react'
import TodoList from './TodoList'

function App() {
  const [todos, setTodos] = useState([])
  const todoNameRef = useRef()

  function handleAddTodo(e) {
    const name = todoNameRef.current.value
    console.log(name)
    if (name === '') return
    setTodos(prevTodos => {
      return [...prevTodos, name]
    })
    todoNameRef.current.value = null
  }

  return (
    <>
      <TodoList todos={todos}/>
      <input ref={todoNameRef} type="text" />
      <button onClick={handleAddTodo}>Add Todo</button>
      <div>0 left to do</div>
    </>
  );
}

export default App;

TodoList.js

export default function TodoList({ todos }) {
	return (
		todos.map(todo => {
			return <div key={todo}>{todo}</div>
		})
	)
}

string to object

현재는 입력한 문자열만 배열에 저장했는데요. 데이타를 변경하거나 삭제하는데 원활한 관리를 위해서 각 문자열에 ID를 부여하도록 하겠습니다. 고유한 ID를 생성하기 위해서 uuid라는 패키지를 node에 설치하도록 할게요. 잠시 코드를 떠나 터미널을 열고 아래의 명령어를 실행합니다.

$ npm install uuid

다시 코드로 돌아와서 uuid패키지를 App.js에 추가해줍니다. uuid패키지에 있는 v4라는 함수인데 여기서는 uuidv4라고 부르도록 import했어요. 그리고 나서 handleAddTodo함수에 배열에 name대신 객체를 넣도록 할게요. 객체는 id, name 그리고 할일을 완료했을때 마킹해주는 complete이라는 변수도 하나 넣을게요. 초기값은 아직 할일이 완료가 안되었으니 false로 설정합니다.

...
import { v4 as uuidv4 } from 'uuid';
...
  function handleAddTodo(e) {
    const name = todoNameRef.current.value
    if (name === '') return
    setTodos(prevTodos => {
      return [...prevTodos, {id: uuidv4(), name: name, complete: false}]
    })
    todoNameRef.current.value = null
  }
...

데이타의 형식이 바뀌었으니 보여지는 쪽에서도 바꿔 주어야겠지요? TodoList.js를 열어서 아래와 같이 변경합니다.

export default function TodoList({ todos }) {
	return (
		todos.map(todo => {
			return <div key={todo.id}>{todo.name}</div>
		})
	)
}

Todo 컴포넌트

이제 각 할일들 앞에 체크박스를 넣어서 일이 완료가 되었는지 마킹을 하도록 할건데요. 코딩을 TodoList.js에서 할수도 있지만 저는 뭐든 그룹그룹 묶어주는게 좋아서요. 체크박스와 할일을 보여주는 한줄짜리 컴포넌트를 만들어서 각 배열방의 값으로 호출해서 보여주도록 하겠습니다. TodoList.js에서 TodoList함수에서 인자로 넘겨받은 todos배열을 하나씩 돌면서 Todo라는 컴포넌트를 호출해서 내용을 구성해보도록하겠습니다.

import Todo from './Todo'

export default function TodoList({ todos }) {
  return (
    todos.map(todo => {
      return <Todo key={todo.id} todo={todo} />
    })
  )
}

아직 Todo컴포넌트가 없으니 만들어 줘야겠죠? 같은 폴더안에 Todo.js를 생성하고 아래와 같이 코딩해주세요.

export default function Todo({ todo }) {
  return (
    <div>
      <label>
        <input type="checkbox" checked={todo.complete} />
        {todo.name}
      </label>
    </div>
  )
}

toggleTodo()

이제 나열된 할일을 완료했을때 체크박스를 클릭해서 업무를 완료 했다고 표시하는 코딩을 한번 해볼게요. 우선 App.js에 toggleTodo라는 이름으로 함수를 하나 선언할게요. 이 함수는 각 할일의 ID를 받아서 해당 ID의 Todo아이템의 값을 배열방에 업데이트 시켜주는 일을 하게 될겁니다.

...
function App() {
...
  function toggleTodo(id) {
    const newTodos = [...todos]
    const todo = newTodos.find(todo => todo.id === id)
    todo.complete = !todo.complete
    setTodos(newTodos)
  }
...

기존의 todos배열을 newTodos에 복사합니다. 그리고 해당 배열을 돌면서 id가 일치하는 객체를 find함수를 통해서 찾아옵니다. 기존에 저장된 complete값의 반대값으로 변경한 뒤 새롭게 만든 배열을 setTodos를 통해서 업데이트 시켜줍니다. 이 함수는 체크박스를 클릭할때마다 호출이 되야하니 이하 컴포넌트에서 사용할수 있도록 TodoList를 호출할때 todos배열과 함께 인자로 전달하도록 하겠습니다.

<TodoList todos={todos} toggleTodo={toggleTodo}/>

그렇다면 TodoList에서도 추가된 인자를 함수에서 받아야겠지요? 그리고 마찬가지로 Todo컴포넌트가 사용할수 있도록 toggleTodo라는 이름으로 또한번 인자를 전달합니다.

import Todo from './Todo'

export default function TodoList({ todos, toggleTodo }) {
  return (
    todos.map(todo => {
      return <Todo key={todo.id} toggleTodo={toggleTodo} todo={todo} />
    })
  )
}

그러면 마지막으로 Todo.js에서도 함수가 호출될때 인자로 받을수 있게 선언을 해줍니다. 그리고 onChange가 될때마다 toggleTodo함수를 호출해주어야하는데, 이때 todo.id도 함께 호출해야하므로 onChange에서 handleTodoClick이라는 함수를 가르키도록 설정하고 handleTodoClick에서는 이 컴포넌트가 호출된 그 todo의 id를 toggleTodo에 함께 넘겨주면서 호출하면 됩니다.

export default function Todo({ todo, toggleTodo }) {
  function handleTodoClick() {
    toggleTodo(todo.id)
  }
  
  return (
    <div>
      <label>
        <input type="checkbox" checked={todo.complete} onChange={handleTodoClick} />
        {todo.name}
      </label>
    </div>
  )
}

App.js에 보시면 출력부분에 텍스트상자 밑에 해야할일이 몇개나 남았는지 보여주도록 정해놓은 곳이 있습니다. 일단 0으로 임시설정해놓은 것을 이제는 배열에서 complete의 값이 마킹이 안되어있는 것만 개수를 세서 보여주도록 하겠습니다. Array에서 제공하는 filter함수에 complete이 false로 세팅된 것들만 filtering을 하는 함수를 넘겨준뒤 filter에서 반환받은 결과 배열의 개수를 세서 아래와 같이 보여주면 됩니다.

<div>{todos.filter(todo => !todo.complete).length} left to do</div>

브라우저 창에서 잘 되는지 확인해보세요. 아래는 현재까지 진행된 코딩입니다.

App.js

import { useState, useRef } from 'react'
import TodoList from './TodoList'
import { v4 as uuidv4 } from 'uuid';

function App() {
  const [todos, setTodos] = useState([])
  const todoNameRef = useRef()

  function toggleTodo(id) {
    const newTodos = [...todos]
    const todo = newTodos.find(todo => todo.id === id)
    todo.complete = !todo.complete
    setTodos(newTodos)
  }

  function handleAddTodo(e) {
    const name = todoNameRef.current.value
    if (name === '') return
    setTodos(prevTodos => {
      return [...prevTodos, {id: uuidv4(), name: name, complete: false}]
    })
    todoNameRef.current.value = null
  }

  return (
    <>
      <TodoList todos={todos} toggleTodo={toggleTodo}/>
      <input ref={todoNameRef} type="text" />
      <button onClick={handleAddTodo}>Add Todo</button>
      <div>{todos.filter(todo => !todo.complete).length} left to do</div>
    </>
  );
}

export default App;

TodoList.js

import Todo from './Todo'

export default function TodoList({ todos, toggleTodo }) {
  return (
    todos.map(todo => {
      return <Todo key={todo.id} toggleTodo={toggleTodo} todo={todo} />
    })
  )
}

Todo.js

export default function Todo({ todo, toggleTodo }) {
  function handleTodoClick() {
    toggleTodo(todo.id)
  }
  
  return (
    <div>
      <label>
        <input type="checkbox" checked={todo.complete} onChange={handleTodoClick} />
        {todo.name}
      </label>
    </div>
  )
}

localStorage

현재 우리가 만든 앱은 브라우저가 새로고침되면 데이타가 다 날아가버리는 코드였자나요. 그렇게 되면 앱으로써의 의미가 없기때문에 새로고침을 해도 다시 방문해도 이전의 데이타를 그대로 볼수 있는 코드로 업그레이드를 해볼게요. 그러기 위해서는 배열이 업데이트 될때마다 변경된 배열값을 local storage에 저장을 해주는 로직이 필요한데요. handleAddTodo나 toggleTodo등의 함수안에 저장하는 코드를 넣을수도 있지만 그렇게 되면 코드가 너무 지저분해지기 때문에 useEffect라는 기능을 이용해서 todos배열이 변경될때마다 정의된 함수를 호출해서 저장하는 작업을 진행하도록 할게요. 일단 react라이브러리에서 useEffect라는 함수를 사용하겠다고 import 합니다. 그리고 useEffect함수를 호출하는데요. 이때, 함수의 첫번째 인자로는 배열이 변경될때마다 호출할 함수를 넘겨주고, 두번째 인자로는 변경을 감지할 배열의 이름을 넘겨줍니다. 두번째 인자의 데이타타입은 배열인데 이유는 여러개의 변수를 감시하면서 같은 함수를 불러주도록 하기 위함입니다. 하지만 우리는 todos하나만 감시하면 되니까 배열안에 todos만 넣어주도록 합니다. 그리고 첫번째 인자로 넘겨주는 함수 안에서 아래와 같이 local storage에 setItem함수를 이용해서 저장할 local storage의 key와 todos의 값을 넣어주는데 이때 값으로는 문자열이 들어가야하므로 JSON.stringify함수를 통해서 JSON을 문자열로 변환한 뒤 setItem에 넣어 호출합니다.

import { useState, useRef, useEffect } from 'react'
...
const LOCAL_STORAGE_KEY = 'todoApp.todos'
...
function App() {
  const [todos, setTodos] = useState(JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY)) || [])
...
  useEffect(() => {
    localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(todos))
  }, [todos])

그리고 App이 실행되고 todos가 초기화 될때 우리는 useState를 이용해서 []로 초기값을 설정했었는데 그 부분을 위의 코드와 같이 localStorage.getItem함수를 통해서 값을 가져오고 해당 값이 문자열이니 JSON.parse를 통해 객체로 만들어 준뒤 todos에 기본값으로 저장되도록 합니다. 이때 localStorage.getItem으로 아무것도 가져오지 못한 경우에는 []로 초기값을 설정해줍니다. 아래는 최종 코드입니다.

App.js

import { useState, useRef, useEffect } from 'react'
import TodoList from './TodoList'
import { v4 as uuidv4 } from 'uuid';


const LOCAL_STORAGE_KEY = 'todoApp.todos'

function App() {
  const [todos, setTodos] = useState(JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY)) || [])
  const todoNameRef = useRef()

  useEffect(() => {
    localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(todos))
  }, [todos])

  function toggleTodo(id) {
    const newTodos = [...todos]
    const todo = newTodos.find(todo => todo.id === id)
    todo.complete = !todo.complete
    setTodos(newTodos)
  }

  function handleAddTodo(e) {
    const name = todoNameRef.current.value
    if (name === '') return
    setTodos(prevTodos => {
      return [...prevTodos, {id: uuidv4(), name: name, complete: false}]
    })
    todoNameRef.current.value = null
  }

  return (
    <>
      <TodoList todos={todos} toggleTodo={toggleTodo}/>
      <input ref={todoNameRef} type="text" />
      <button onClick={handleAddTodo}>Add Todo</button>
      <div>{todos.filter(todo => !todo.complete).length} left to do</div>
    </>
  );
}

export default App;

TodoList.js

import Todo from './Todo'

export default function TodoList({ todos, toggleTodo }) {
  return (
    todos.map(todo => {
      return <Todo key={todo.id} toggleTodo={toggleTodo} todo={todo} />
    })
  )
}

Todo.js

export default function Todo({ todo, toggleTodo }) {
  function handleTodoClick() {
    toggleTodo(todo.id)
  }
  
  return (
    <div>
      <label>
        <input type="checkbox" checked={todo.complete} onChange={handleTodoClick} />
        {todo.name}
      </label>
    </div>
  )
}

자 이제 브라우저 화면을 새로고침해도, 심지어 닫았다 다시 열어도 TodoList는 입력한 상태 그대로 보존이 됩니다. TodoList를 삭제하고 변경하는 부분은 배운 내용들을 바탕으로 직접 한번 구현해보세요. 끝까지 읽어주셔서 감사합니다.

Resource: https://youtu.be/hQAHSlTtcmY

Understanding Array.map()

자바스크립트 함수들을 가끔 보다보면 코드가 너무 많이 생략이 되어있어서 읽기 힘든 경우가 종종 있습니다. 그중에 하나가 Array.map()과 같은 함수가 되겠는데요. 아래는 배열의 각 아이템에 2씩 곱해서 새로운 배열을 만드는 코드입니다.

const numbers = [1, 4, 9];
const doubles = numbers.map(num => num * 2);

numbers라는 배열을 초기화하고, Array에서 제공하는 map이라는 함수를 사용해서 doubles라는 새로운 배열을 만드는데요. 여기서 map의 인자로 들어가는 코드를 보면 함수가 들어가 있습니다. 이 형식이 함수라고 인지하지 못하는 경우에는 num이라는 변수가 정의된 적이 없는데 왜 여기서 사용할수 있는 거지? 하고 헷갈릴수 있어요. 위의 코드를 아래와 같이 바꾸면 이제 정의된 함수를 넘겨주고 있다는걸 알아차릴수 있으시죠?

const numbers = [1, 4, 9];
const doubles = numbers.map((num) => {num * 2});

더 명확히 구분하기 위해서 아래와 같이 더 풀어서 코딩할수도 있습니다.

const numbers = [1, 4, 9];
const doubles = numbers.map(makeDouble);
function makeDouble(num) {
   return num * 2;
}

map함수를 실행하면 인자로 받은 makeDouble을 실행하는데 이때 makeDouble에 인자로 들어가는 것이 바로 각 배열의 아이템인데 이것을 임의의 이름, num으로 부르겠다고 정의한거에요. 이렇게 써놓고 보니까 좀더 make sense하죠? map은 배열안의 아이템을 하나씩 돌면서 makeDouble함수를 실행해서 결과값을 각 배열에 상응하는 배열방에 저장한뒤 반환하는 함수가 되겠습니다.

기존의 컨셉처럼 함수는 언제나 변수를 인자로 받고 결과값을 반환하는것이 아니라 Array.map()처럼 요즘세대에는 인자로 함수를 넘겨받고 해당 함수를 이용해서 어떤 특정한 액션을 제공하는 기본 함수들이 참 많이 나와 있습니다. 옛날에 코딩 시작하신 분들에게는 조금 헷갈릴수 있는 부분이라 짚고 넘어갑니다.

Installing Node on Mac

현재 컴퓨터에 Node가 설치되어있는지 우선 확인할게요. 아래 명령어는 노드가 이미 설치되어있다면 버젼을 보여주겠지만 설치되어있지 않은 경우에는 아래와 같이 command not found에러가 납니다.

$ node -v
-bash: node: command not found

제 컴퓨터는 Mac이라서 Homebrew를 이용해서 설치합니다.

$ brew install node

설치가 완료되면 확인을 해보세요.

$ node -v
v18.9.0

homebrew로 node를 설치하면 각종 패키지들을 설치할수 있게 도와주는 npm와 패키지를 실행하는데 필요한 npx도 함께 설치가 됩니다.

$ npm -v
8.19.1
$ npx -v
8.19.1

이상 Mac에 node와 npm을 설치하는 방법이었습니다.

How to add a user in MySQL

mysql> CREATE USER 'tutorial'@'localhost' IDENTIFIED BY 'PassWord123!!!';

tutorial은 사용자 ID이고 localhost는 접속하는 서버가 로컬에 있는지 원격에서의 접속을 허용할지를 정하는 것입니다. 현재 우리는 웹서버와 DB서버가 하나의 장비에 위치하고 있으므로 localhost만 적어도 접속하는데 아무런 문제가 없습니다. 하지만 호스팅업체등 MySQL서버와 웹서버가 서로 다른 위치에 있는 경우에는 접속하는 서버의 주소를 지정할수 있습니다.

위의 명령어로 사용자를 추가하면 해당 사용자는 아무런 권한도 없는채 생성이 됩니다. 이제 해당 사용자에게 권한을 부여하고자 하는데요. 아래와 같이 명령한다면 해당 사용자에게 모든 데이타베이스의 모든 권한을 부여하게 되어 위험할수 있습니다. 가급적 권한은 꼭 필요한 것만 주도록 하세요.

mysql> GRANT ALL PRIVILEGES ON *.* TO 'tutorial'@'localhost' WITH GRANT OPTION;

그렇다면 가장 중요한 권한은 해당 사용자가 접속할 데이타베이스를 지정해주는 것입니다.

mysql> GRANT CREATE, ALTER, DROP, INSERT, UPDATE, DELETE, SELECT on tutorial.* TO 'tutorial'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> SHOW GRANTS FOR 'tutorial'@'localhost';

만약 이미 부여한 권한을 빼앗고 싶다면 특정권한을 지정하거나, 아래의 두번째 REVOKE명령과 같이 ALL PRIVILEGES를 빼앗을수도 있습니다.

mysql> REVOKE SELECT ON tutorial.* FROM 'tutorial'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> SHOW GRANTS FOR 'tutorial'@'localhost';

mysql> REVOKE ALL PRIVILEGES ON tutorial.* FROM 'tutorial'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> SHOW GRANTS FOR 'tutorial'@'localhost';

사용자가 더이상 필요하지 않다면 삭제는 아래와 같이 합니다.

mysql> DROP USER 'tutorial'@'localhost';