8. 복합문(Compound statements)

복합문은 다른 문장들(의 그룹들)을 포함합니다; 어떤 방법으로 그 다른 문장들의 실행에 영향을 주거나 제어합니다. 간단하게 표현할 때, 전체 복합문을 한 줄로 쓸 수 있기는 하지만, 일반적으로 복합문은 여러 줄에 걸칩니다.

if, while, for 문장은 전통적인 제어 흐름 구조를 구현합니다. 문장들의 그룹에 대해 try 는 예외 처리기나 정리(cleanup) 코드 또는 그 둘 모두를 지정하는 반면, with 문은 코드 블록 주변으로 초기화와 파이널리제이션 코드를 실행할 수 있도록 합니다. 함수와 클래스 정의 또한 문법적으로 복합문입니다.

복합문은 하나나 그 이상의 '절'로 구성됩니다. 절은 헤더와 '스위트(suite)'로 구성됩니다. 특정 복합문의 절 헤더들은 모두 같은 들여쓰기 수준을 갖습니다. 각 절 헤더는 특별하게 식별되는 키워드로 시작하고 콜론으로 끝납니다. 스위트는 절에 의해 제어되는 문장들의 그룹입니다. 스위트는 헤더의 콜론 뒤에서 같은 줄에 세미콜론으로 분리된 하나나 그 이상의 단순문일 수 있습니다. 또는 그다음 줄에 들여쓰기 된 하나나 그 이상의 문장들일 수도 있습니다. 오직 후자의 형태만 중첩된 복합문을 포함할 수 있습니다; 다음과 같은 것은 올바르지 않은데, 대체로 뒤따르는 else 절이 있다면 어떤 if 절에 속하는지 명확하지 않기 때문입니다.

if test1: if test2: print(x)

또한, 이 문맥에서 세미콜론이 콜론보다 더 강하게 결합해서, 다음과 같은 예에서, print() 호출들은 모두 실행되거나 어느 하나도 실행되지 않습니다는 것에 주의해야 합니다:

if x < y < z: print(x); print(y); print(z)

요약하면:

compound_stmt ::=  if_stmt
                   | while_stmt
                   | for_stmt
                   | try_stmt
                   | with_stmt
                   | funcdef
                   | classdef
                   | async_with_stmt
                   | async_for_stmt
                   | async_funcdef
suite         ::=  stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
statement     ::=  stmt_list NEWLINE | compound_stmt
stmt_list     ::=  simple_stmt (";" simple_stmt)* [";"]

문장들이 항상 NEWLINE 으로 끝나고 DEDENT 가 그 뒤를 따를 수 있음에 주목해야 합니다. 또한, 생략 가능한 연결 절들이 항상 문장을 시작시킬 수 없는 키워드로 시작하기 때문에, 모호함이 없다는 것도 주목하세요 (파이썬에서는 중첩된 if 문이 들여쓰기 되는 것을 요구함으로써 '매달린(dangling) else' 문제를 해결합니다).

flowdas

'매달린(dangling) else' 문제는, if 문이 중첩될 때, 뒤 따르는 else 가 어떤 if 와 결합하는지 모호함이 발생할 수 있다는 것입니다. 많은 언어들에서는 괄호를 사용한 구조를 통해 모호함을 제거하는 반면, 파이썬에서는 들여쓰기로 해결합니다.

명확함을 위해 다음에 오는 절들에서 나오는 문법 규칙들은 각 절을 별도의 줄에 놓도록 포매팅합니다.

8.1. if

if 문은 조건부 실행에 사용됩니다:

if_stmt ::=  "if" assignment_expression ":" suite
             ("elif" assignment_expression ":" suite)*
             ["else" ":" suite]

참이 되는 것을 발견할 때까지 표현식들의 값을 하나씩 차례대로 구해서 정확히 하나의 스위트를 선택합니다 (참과 거짓의 정의는 논리 연산(Boolean operations) 섹션을 보세요); 그런 다음 그 스위트를 실행합니다 (그리고는 if 문의 다른 어떤 부분도 실행되거나 값이 구해지지 않습니다). 모든 표현식들이 거짓이면 else 절의 스위트가 (있다면) 실행됩니다.

8.2. while

while 문은 표현식이 참인 동안 실행을 반복하는 데 사용됩니다:

while_stmt ::=  "while" assignment_expression ":" suite
                ["else" ":" suite]

이것은 표현식을 반복적으로 검사하고, 참이면, 첫 번째 스위트를 실행합니다; 표현식이 거짓이면 (처음부터 거짓일 수도 있습니다) else 절의 스위트가 (있다면) 실행되고 루프를 종료합니다.

첫 번째 스위트에서 실행되는 break 문은 else 절을 실행하지 않고 루프를 종료합니다. 첫 번째 스위트에서 실행되는 continue 문은 스위트의 나머지 부분을 건너뛰고 표현식의 검사로 돌아갑니다.

8.3. for

for 문은 (문자열, 튜플, 리스트 같은) 시퀀스 나 다른 이터러블 객체의 요소들을 이터레이트하는데 사용됩니다:

for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

표현식 목록은 한 번만 값이 구해집니다; 이터러블 객체가 나와야 합니다. expression_list 의 결과로 이터레이터가 만들어집니다. 그런 다음 이터레이터가 제공하는 항목마다, 이터레이터가 돌려주는 순서대로, 스위트가 한 번씩 실행됩니다. 순환마다 각 항목이 대입의 표준 규칙 (대입문 을 보세요) 으로 타깃 목록에 대입된 다음, 스위트가 실행됩니다. 항목들이 소진되었을 때 (이터레이터가 StopIteration 예외를 일으킬 때나 빈 시퀀스인 경우는 즉시 발생합니다), the else 절의 스위트가 (있다면) 실행되고 루프를 종료합니다.

첫 번째 스위트에서 실행되는 break 문은 else 절을 실행하지 않고 루프를 종료합니다. 첫 번째 스위트에서 실행되는 continue 문은 스위트의 나머지 부분을 건너뛰고 다음 항목으로 넘어가거나, 다음 항목이 없으면 else 절로 갑니다.

for-루프는 타깃 목록의 변수들에 대입합니다. for-루프의 스위트에서 이루어진 것들도 포함해서, 그 변수에 앞서 대입된 값들을 모두 덮어씁니다:

for i in range(10):
    print(i)
    i = 5             # 이렇게 해도 범위내의 다음 인덱스로
                      # 덮어쓰기 때문에 for-루프에
                      # 영향을 주지 않습니다

타깃 목록의 이름들은 루프가 종료될 때 삭제되지 않지만, 시퀀스가 비어있다면, 루프에 의해 전혀 대입이 일어나지 않을 수도 있습니다. 힌트: 내장 함수 range() 는 파스칼의 for i := a to b do 의 효과를 흉내 내는데 적합한 정수의 이터레이터를 돌려줍니다; 예를 들어, list(range(3)) 는 리스트 [0, 1, 2] 를 돌려줍니다.

참고

시퀀스가 루프에 의해 수정될 때는 미묘한 점이 있습니다 (이것은 오직 가변 시퀀스에서만 일어납니다, 가령 리스트). 다음에 어떤 항목이 사용될지를 추적하는 내부 카운터가 사용되고, 각 이터레이션마다 증가합니다. 이 카운터가 시퀀스의 길이에 도달하면 루프가 종료됩니다. 이것은 만약 스위트가 시퀀스에서 현재 (또는 그 이전의) 항목을 삭제하면, 다음 항목을 건너뛰게 된다는 뜻입니다 (다음 항목이 이미 다뤄진 현재 항목의 인덱스를 갖게 되기 때문입니다). 마찬가지로, 스위트가 현재 항목 앞으로 시퀀스에 항목을 삽입하면, 현재 항목은 루프의 다음 순환에서 현재 항목이 한 번 더 다뤄지게 됩니다. 이것은 고약한 버그로 이어질 수 있는데, 전체 시퀀스의 슬라이스로 임시 사본을 만듦으로써 피할 수 있습니다, 예를 들어

for x in a[:]:
    if x < 0: a.remove(x)

flowdas

본문에서 언급하고 있는 카운터는 for-루프가 유지하는 것이 아닙니다. 이 카운터를 유지하는 것은 시퀀스의 이터레이터입니다. 때문에 for-루프 자체의 문제가 아니라 시퀀스의 이터레이터가 갖고 있는 문제입니다.

8.4. try

try 문은 문장 그룹에 대한 예외 처리기나 정리(cleanup) 코드 또는 그 둘 모두를 지정하는 데 사용됩니다.

try_stmt  ::=  try1_stmt | try2_stmt
try1_stmt ::=  "try" ":" suite
               ("except" [expression ["as" identifier]] ":" suite)+
               ["else" ":" suite]
               ["finally" ":" suite]
try2_stmt ::=  "try" ":" suite
               "finally" ":" suite

except 절(들)은 하나나 그 이상의 예외 처리기를 지정합니다. try 절에서 예외가 발생하지 않으면 아무런 예외 처리기도 실행되지 않습니다. try 스위트에서 예외가 발생할 때, 예외 처리기 검색이 시작됩니다. 이 검색은 그 예외에 매치되는 것을 발견할 때까지 except 절을 차례대로 들여다봅니다. 표현식이 없는 except 절이 있다면 가장 마지막에 와야 합니다; 모든 예외와 매치됩니다. 표현식이 있는 except 절의 경우, 표현식의 값을 구하고, 결과 객체가 예외와 "호환" 되면 그 절이 예외에 매치됩니다. 객체는 예외 객체의 클래스나 베이스 클래스일 때, 또는 예외 객체의 클래스나 베이스 클래스인 항목을 포함한 튜플일 때 예외와 호환됩니다.

except 절 중 어느 것도 예외와 매치되지 않으면, 예외 처리기 검색은 둘러싼 코드와 호출 스택에서 계속됩니다. 1

만약 except 절의 헤더에 있는 표현식의 값을 구할 때 예외가 발생하면, 원래의 처리기 검색은 취소되고 둘러싼 코드와 호출 스택에서 새 예외에 대해 검사가 시작됩니다 (try 문 전체가 예외를 일으킨 것으로 취급됩니다).

매치되는 except 절이 발견되면, 예외는 그 except 절에 있는 as 키워드 (가 있다면) 뒤에 지정된 타깃에 대입되고, except 절의 스위트가 실행됩니다. 모든 except 절은 실행 가능한 블록을 가져야 합니다. 블록의 끝에 도달하면, try 문 전체의 뒤에서 일반적인 실행이 계속됩니다. (이것은 같은 예외에 대해 두 개의 중첩된 처리기가 있고, 예외가 안쪽 처리기의 try 절에서 발생했다면, 바깥 처리기는 예외를 처리하지 않게 된다는 뜻이 됩니다.)

예외가 as target 을 사용해서 대입될 때, except 절 끝에서 삭제됩니다. 이것은 마치

except E as N:
    foo

가 이렇게 변환되는 것과 같습니다

except E as N:
    try:
        foo
    finally:
        del N

이것은 except 절 후에 참조하려면 예외를 다른 이름에 대입해야 한다는 뜻입니다. 예외를 제거하는 이유는, 그것에 첨부된 트레이스백으로 인해, 스택 프레임과 참조 순환을 형성해서 다음 가비지 수거가 일어나기 전까지 그 프레임의 모든 지역 변수들을 잡아두기 때문입니다.

except 절의 스위트가 실행되기 전에, 예외의 상세 내용이 sys 모듈에 저장되는데, sys.exc_info() 를 통해 액세스할 수 있습니다. sys.exc_info() 는 예외 클래스, 예외 인스턴스, 예외가 프로그램의 어디에서 발생했는지를 알려주는 트레이스백 객체 (표준형 계층 를 보세요) 로 이루어진 3-튜플을 돌려줍니다. sys.exc_info() 값들은 예외를 처리한 함수로부터 복귀할 때 이전 값으로 복구됩니다.

생략 가능한 else 절은 제어 흐름이 try 스위트를 빠져나가고, 예외가 발생하지 않았고, return, continue 또는 break 문이 실행되지 않으면 실행됩니다. else 절에서 발생하는 예외는 앞에 나오는 except 절에서 처리되지 않습니다.

finally 가 있으면, '정리(cleanup)' 처리기를 지정합니다. exceptelse 절을 포함해서, 먼저 try 절이 실행됩니다. 이 절들의 어디에서건 예외가 일어나면, 예외는 임시 저장됩니다. finally 절이 실행됩니다. 만약 저장된 예외가 있으면, finally 절의 끝에서 다시 발생시킨다. finally 절이 다른 예외를 일으키면, 저장된 예외는 새 예외의 컨텍스트(context) 로 설정됩니다. finally 절이 return, break 또는 continue 문을 실행하면, 저장된 예외는 버립니다.

>>> def f():
...     try:
...         1/0
...     finally:
...         return 42
...
>>> f()
42

flowdas

finally 절에서 return 이나 break 가 실행되면 try 문은 어떤 예외도 확산시키지 않습니다. 예외가 try 스위트에서 발생하건, except 절의 표현식의 값을 구할 때 발생하건 마찬가지입니다.

finally 절을 실행하는 동안 예외 정보는 프로그램에 제공되지 않습니다.

try...finally 문의 try 스위트에서 return, break, continue 문이 실행될 때, finally 절도 '나가는 길에' 실행됩니다.

함수의 반환 값은 마지막에 실행된 return 문으로 결정됩니다. finally 절이 항상 실행되기 때문에, finally 절에서 실행되는 return 문이 항상 마지막에 실행되는 것이 됩니다:

>>> def foo():
...     try:
...         return 'try'
...     finally:
...         return 'finally'
...
>>> foo()
'finally'

예외에 관한 추가의 정보는 예외 섹션에서 찾을 수 있고, 예외를 일으키기 위해 raise 문을 사용하는 것에 관한 정보는 raise 문 섹션에서 찾을 수 있습니다.

버전 3.8에서 변경: 파이썬 3.8 이전에는, finally 문이 구현 문제로 인해 finally 절에서 유효하지 않았습니다.

8.5. with

with 문은 블록의 실행을 컨텍스트 관리자 (with 문 컨텍스트 관리자 섹션을 보세요) 가 정의한 메서드들로 감싸는 데 사용됩니다. 이것은 흔한 try...except...finally 사용 패턴을 편리하게 재사용할 수 있도록 캡슐화할 수 있도록 합니다.

with_stmt ::=  "with" with_item ("," with_item)* ":" suite
with_item ::=  expression ["as" target]

하나의 "item" 을 사용하는 with 문의 실행은 다음과 같이 진행됩니다:

  1. 컨텍스트 관리자를 얻기 위해 컨텍스트 표현식 (with_item 에 주어진 expression) 의 값을 구합니다.

  2. 나중에 사용하기 위해 컨텍스트 관리자의 __enter__() 가 로드됩니다.

  3. 나중에 사용하기 위해 컨텍스트 관리자의 __exit__() 가 로드됩니다.

  4. 컨텍스트 관리자의 __enter__() 메서드를 호출합니다.

  5. with 문에 타깃이 포함되었으면, 그것에 __enter__() 의 반환 값을 대입합니다.

    참고

    with 문은 __enter__() 메서드가 에러 없이 돌아왔을 때, __exit__() 가 항상 호출됨을 보장합니다. 그래서, 타깃에 대입하는 동안 에러가 발생하면, 스위트 안에서 에러가 발생한 것과 같이 취급됩니다. 아래의 6단계를 보세요.

  6. 스위트가 실행됩니다.

  7. 컨텍스트 관리자의 __exit__() 메서드를 호출합니다. 예외가 스위트를 종료되도록 만들었다면, 그것의 형, 값, 트레이스백이 __exit__() 의 인자로 전달됩니다. 그렇지 않으면 세 개의 None 이 인자로 공급됩니다.

    스위트가 예외 때문에 종료되었고, __exit__() 메서드의 반환 값이 거짓이면, 그 예외를 다시 일으킨다. 반환 값이 참이면, 예외를 억누르고, with 문 뒤에 오는 문장으로 실행을 계속합니다.

    스위트가 예외 이외의 이유로 종료되면, __exit__() 의 반환 값은 무시되고, 해당 종료의 종류에 맞는 위치에서 실행을 계속합니다.

다음과 같은 코드는:

with EXPRESSION as TARGET:
    SUITE

의미상으로 다음과 동등합니다:

manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
hit_except = False

try:
    TARGET = value
    SUITE
except:
    hit_except = True
    if not exit(manager, *sys.exc_info()):
        raise
finally:
    if not hit_except:
        exit(manager, None, None, None)

하나 보다 많은 항목을 주면, 컨텍스트 관리자는 with 문이 중첩된 것처럼 진행합니다:

with A() as a, B() as b:
    SUITE

의미상으로 다음과 동등합니다:

with A() as a:
    with B() as b:
        SUITE

버전 3.1에서 변경: 다중 컨텍스트 표현식의 지원

더 보기

PEP 343 - "with" 문

파이썬 with 문의 규격, 배경, 예.

8.6. 함수 정의

함수 정의는 사용자 정의 함수 객체 (표준형 계층 섹션을 보세요) 를 정의합니다:

funcdef                   ::=  [decorators] "def" funcname "(" [parameter_list] ")"
                               ["->" expression] ":" suite
decorators                ::=  decorator+
decorator                 ::=  "@" assignment_expression NEWLINE
dotted_name               ::=  identifier ("." identifier)*
parameter_list            ::=  defparameter ("," defparameter)* "," "/" ["," [parameter_list_no_posonly]]
                                 | parameter_list_no_posonly
parameter_list_no_posonly ::=  defparameter ("," defparameter)* ["," [parameter_list_starargs]]
                               | parameter_list_starargs
parameter_list_starargs   ::=  "*" [parameter] ("," defparameter)* ["," ["**" parameter [","]]]
                               | "**" parameter [","]
parameter                 ::=  identifier [":" expression]
defparameter              ::=  parameter ["=" expression]
funcname                  ::=  identifier

함수 정의는 실행할 수 있는 문장입니다. 실행하면 현재 지역 이름 공간의 함수 이름을 함수 객체 (함수의 실행 가능한 코드를 둘러싼 래퍼(wrapper)). 이 함수 객체는 현재의 이름 공간에 대한 참조를 포함하는데, 함수가 호출될 때 전역 이름 공간으로 사용됩니다.

함수 정의는 함수의 바디를 실행하지 않습니다. 함수가 호출될 때 실행됩니다. 2

함수 정의는 하나나 그 이상의 데코레이터 표현식으로 감싸질 수 있습니다. 데코레이터 표현식은 함수가 정의될 때, 함수 정의를 포함하는 스코프에서 값을 구합니다. 그 결과는 콜러블이어야 하는데, 함수 객체만을 인자로 사용해서 호출됩니다. 반환 값이 함수 객체 대신 함수의 이름에 연결됩니다. 여러 개의 데코레이터는 중첩되는 방식으로 적용됩니다. 예를 들어, 다음과 같은 코드

@f1(arg)
@f2
def func(): pass

는 대략 다음과 동등합니다

def func(): pass
func = f1(arg)(f2(func))

원래의 함수가 임시로 이름 func 에 연결되지 않는다는 점만 다릅니다.

버전 3.9에서 변경: 함수는 모든 유효한 assignment_expression으로 데코레이트 될 수 있습니다. 이전에는, 문법이 훨씬 제한적이었습니다; 자세한 내용은 PEP 614를 참조하십시오.

하나나 그 이상의 매개변수 들이 parameter = expression 형태를 가질 때, 함수가 "기본 매개변수 값"을 갖는다고 말합니다. 기본값이 있는 매개변수의 경우, 호출할 때 대응하는 인자 를 생략할 수 있고, 그럴 때 매개변수의 기본값이 적용됩니다. 만약 매개변수가 기본값을 가지면, "*" 까지 그 뒤를 따르는 모든 매개변수도 기본값을 가져야 합니다 --- 이것은 문법 규칙에서 표현되지 않는 문법적 제약입니다.

함수 정의가 실행될 때, 기본 매개변수 값은 왼쪽에서 오른쪽으로 값이 구해집니다. 이것은 표현식이 함수가 정의될 때 한 번 값이 구해지고, 호출마다 같은 "미리 계산된" 값이 사용된다는 것을 뜻합니다. 이것을 이해하는 것은 특히 기본값이 리스트나 딕셔너리와 같은 가변 객체일 때 중요합니다: 만약 함수가 그 객체를 수정하면 (가령, 리스트에 항목을 추가합니다), 그 결과 기본값이 수정됩니다. 이것은 일반적으로 의도하고 있는 것이 아니다. 이 문제를 회피하는 방법은 기본값으로 None 을 사용하고, 함수 바디에서 명시적으로 검사하는 것입니다, 예를 들어:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

함수 호출의 의미는 섹션 호출 에서 더 자세히 설명됩니다. 함수 호출은 항상 매개변수 목록에서 언급하는 모든 매개변수에 값을 대입하는데, 위치 인자들에서 올 수도, 키워드 인자들에서 올 수도, 기본값에서 올 수도 있습니다. "*identifier" 형태가 존재하면, 남는 위치 매개변수들을 받는 튜플로 초기화됩니다. 기본값은 빈 튜플입니다. "**identifier" 형태가 존재하면, 남는 키워드 인자들을 받는 순서 있는 매핑으로 초기화됩니다. 기본값은 빈 매핑입니다. "*" 나 "*identifier" 뒤에 오는 매개변수들은 키워드 전용 매개변수들이고, 키워드 인자로만 전달될 수 있습니다.

flowdas

"**identifier" 형태는 순서있는 매핑입니다. 즉 키워드 인자들이 주어진 순서가 보존됩니다. 현재 구현에서는 dict 가 넘어오는데, dict 는 순서있는 매핑입니다.

매개변수들은 매개변수 이름 뒤에 오는 ": expression" 형태의 어노테이션을 가질 수 있습니다. 모든 매개변수는 어노테이션을 가질 수 있는데, *identifier**identifier 형태조차 그렇습니다. 함수는 매개변수 목록 뒤에 오는 "-> expression" 형태의 반환("return") 어노테이션을 가질 수 있습니다. 이 어노테이션들은 올바른 파이썬 표현식이면 어떤 것이건 될 수 있습니다. 어노테이션의 존재는 함수의 의미를 바꾸지 않습니다. 어노테이션 값들은 함수 객체의 __annotations__ 어트리뷰트에서 매개변수의 이름을 키로 하는 딕셔너리의 값으로 제공됩니다. __future__ 에서 annotations 을 임포트하면, 지연된 평가가 활성화되어 어노테이션은 실행시간에 문자열로 보존됩니다. 그렇지 않으면 함수 정의가 실행될 때 평가됩니다. 이 경우 어노테이션은 소스 코드에 나오는 순서와 다른 순서로 평가될 수 있습니다.

표현식에서 즉시 사용하기 위해, 이름 없는 함수(이름에 연결되지 않은 함수)를 만드는 것도 가능합니다. 이것은 람다 표현식을 사용하는데, 람다(Lambdas) 섹션에서 설명합니다. 람다 표현식은 단순화된 함수 정의를 위한 줄임 표현에 지나지 않는다는 것에 주의하세요; "def" 문장에서 정의된 함수는 람다 표현식으로 정의된 함수처럼 전달되거나 다른 이름에 대입될 수 있습니다. 여러 개의 문장을 실행하는 것과 어노테이션을 허락하기 때문에, "def" 형태가 사실 더 강력합니다.

프로그래머 유의 사항: 함수는 퍼스트 클래스(first-class) 객체다. 함수 정의 안에서 실행되는 "def" 문은 돌려주거나 전달할 수 있는 지역 함수를 정의합니다. 중첩된 함수에서 사용되는 자유 변수들은 그 def 를 포함하는 함수의 지역 변수들을 액세스할 수 있습니다. 더 자세한 내용은 이름과 연결(binding) 섹션을 보세요.

더 보기

PEP 3107 - 함수 어노테이션

함수 어노테이션의 최초 규격.

PEP 484 - 형 힌트

어노테이션에 대한 표준 의미 정의: 형 힌트.

PEP 526 - 변수 어노테이션 문법

클래스 변수 및 인스턴스 변수를 포함하는 변수 선언에 형 힌트를 줄 수 있는 기능

PEP 563 - 어노테이션의 지연된 평가

즉시 평가하는 대신 실행시간에 어노테이션을 문자열 형식으로 보존하여 어노테이션 내에서의 전방 참조를 지원합니다.

8.7. 클래스 정의

클래스 정의는 클래스 객체(표준형 계층 섹션을 보세요)를 정의합니다:

classdef    ::=  [decorators] "class" classname [inheritance] ":" suite
inheritance ::=  "(" [argument_list] ")"
classname   ::=  identifier

클래스 정의는 실행 가능한 문장입니다. 계승(inheritance) 목록은 보통 베이스 클래스들의 목록을 제공하는데 (더 고급 사용에 대해서는 메타 클래스 를 보세요), 목록의 각 항목은 값을 구할 때 서브 클래싱을 허락하는 클래스 객체가 되어야 합니다. 계승 목록이 없는 클래스는, 기본적으로, 베이스 클래스 object 를 계승합니다; 그래서

class Foo:
    pass

는 다음과 동등합니다

class Foo(object):
    pass

클래스의 스위트는 새로 만들어진 지역 이름 공간과 원래의 전역 이름 공간을 사용하는 새 실행 프레임 (이름과 연결(binding) 을 보세요)에서 실행됩니다. (보통, 스위트는 대부분 함수 정의들을 포함합니다.) 클래스의 스위트가 실행을 마치면, 실행 프레임은 파기하지만, 그것의 지역 이름 공간은 보존합니다. 3 그런 다음, 계승 목록을 베이스 클래스들로, 보존된 지역 이름 공간을 어트리뷰트 딕셔너리로 사용해서 새 클래스 객체를 만듭니다. 클래스의 이름은 원래의 지역 이름 공간에서 이 클래스 객체와 연결됩니다.

클래스 바디에서 어트리뷰트가 정의되는 순서는, 새 클래스의 __dict__ 에 보존됩니다. 이것은 클래스가 만들어진 직후에, 정의 문법을 사용해서 정의되는 클래스들에서만 신뢰할 수 있다는 것에 주의해야 합니다.

flowdas

클래스 어트리뷰트의 순서가 __dict__ 에 보존되는 것 역시, dict 가 삽입순서를 보존한다는 것에 의존합니다. 하지만 이 보존 상태는 클래스가 만들어지는 직후에만 보장될 뿐, 그 이후의 어느 시점엔가 __dict__ 가 애초의 순서를 보존하지 않는 상태로 바뀔 수도 있음을 시사하고 있습니다. 이 직후라는 것은 보통 object.__init_subclass__() 가 호출되는 시점이나, 그 근처를 뜻합니다. 또한 클래스 정의 문법을 사용하지 않는 경우에는 이 순서의 보존이 보장되지 않는다고 말하고 있는데, 클래스 정의 문법을 사용하지 않는다는 것은 메타클래스를 사용해서 동적으로 클래스를 만드는 경우입니다.

클래스 생성은 메타 클래스 를 사용해서 심하게 커스터마이즈할 수 있습니다.

클래스 역시 함수를 데코레이팅할 때처럼 테코레이트할 수 있습니다,

@f1(arg)
@f2
class Foo: pass

는 대략 다음과 동등합니다

class Foo: pass
Foo = f1(arg)(f2(Foo))

데코레이터 표현식의 값을 구하는 규칙은 함수 데코레이터와 같습니다. 그런 다음 그 결과가 클래스 이름에 연결됩니다.

버전 3.9에서 변경: 클래스는 모든 유효한 assignment_expression으로 데코레이트 될 수 있습니다. 이전에는, 문법이 훨씬 제한적이었습니다; 자세한 내용은 PEP 614를 참조하십시오.

프로그래머 유의 사항: 클래스 정의에서 정의되는 변수들은 클래스 어트리뷰트입니다; 이것들은 인스턴스 간에 공유됩니다. 인스턴스 어트리뷰트는 메서드에서 self.name = value 로 설정될 수 있습니다. 클래스와 인스턴스 어트리뷰트 모두 "self.name" 표기법으로 액세스할 수 있고, 이런 식으로 액세스할 때 인스턴스 어트리뷰트는 같은 이름의 클래스 어트리뷰트를 가립니다. 클래스 어트리뷰트는 인스턴스 어트리뷰트의 기본값으로 사용될 수 있지만, 가변 값을 사용하는 것은 예상하지 않은 결과를 줄 수 있습니다. 디스크립터 를 다른 구현 상세를 갖는 인스턴스 변수를 만드는데 사용할 수 있습니다.

더 보기

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

메타 클래스 선언을 현재 문법으로 변경하고, 메타 클래스가 있는 클래스를 구성하는 방법의 의미를 변경하는 제안.

PEP 3129 - 클래스 데코레이터

클래스 데코레이터를 추가하는 제안. 함수와 메서드 데코레이터는 PEP 318에서 도입되었습니다.

8.8. 코루틴

버전 3.5에 추가.

8.8.1. 코루틴 함수 정의

async_funcdef ::=  [decorators] "async" "def" funcname "(" [parameter_list] ")"
                   ["->" expression] ":" suite

파이썬 코루틴의 실행은 여러 지점에서 일시 중지되거나 재개될 수 있습니다 (코루틴 을 보세요.). 코루틴의 바디 안에서, awaitasync 식별자는 예약 키워드가 됩니다; 어웨이트(await) 표현식, async for, async with 는 코루틴 바디에서만 사용할 수 있습니다.

flowdas

“코루틴의 바디에서, awaitasync 식별자는 예약 키워드가 된다” 는 뜻은, awaitasync 를 그 밖의 다른 곳에서는 키워드가 아닌 일반 식별자로 쓸 수 있다는 뜻인데, 이는 파이썬 3.6 까지만 그렇고, 3.7 부터는 키워드로 변경되었습니다.

async def 문법으로 정의된 함수는 항상 코루틴 함수인데, awaitasync 키워드를 포함하지 않는 경우도 그렇습니다.

코루틴 함수의 바디 안에서 yield from 표현식을 사용하는 것은 SyntaxError 입니다.

코루틴 함수의 예:

async def func(param1, param2):
    do_stuff()
    await some_coroutine()

8.8.2. async for

async_for_stmt ::=  "async" for_stmt

비동기 이터러블비동기 이터레이터 를 직접 반환하는 __aiter__ 메서드를 제공하고, 비동기 이터레이터는 자신의 __anext__ 메서드에서 비동기 코드를 호출할 수 있습니다.

async for 문은 비동기 이터러블에 대한 편리한 이터레이션을 허락합니다.

다음과 같은 코드는:

async for TARGET in ITER:
    SUITE
else:
    SUITE2

의미상으로 다음과 동등합니다:

iter = (ITER)
iter = type(iter).__aiter__(iter)
running = True

while running:
    try:
        TARGET = await type(iter).__anext__(iter)
    except StopAsyncIteration:
        running = False
    else:
        SUITE
else:
    SUITE2

더 자세한 내용은 __aiter__()__anext__() 보면 됩니다.

코루틴 함수의 바디 밖에서 async for 문을 사용하는 것은 SyntaxError 입니다.

8.8.3. async with

async_with_stmt ::=  "async" with_stmt

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

다음과 같은 코드는:

async with EXPRESSION as TARGET:
    SUITE

의미상으로 다음과 동등합니다:

manager = (EXPRESSION)
aenter = type(manager).__aenter__
aexit = type(manager).__aexit__
value = await aenter(manager)
hit_except = False

try:
    TARGET = value
    SUITE
except:
    hit_except = True
    if not await aexit(manager, *sys.exc_info()):
        raise
finally:
    if not hit_except:
        await aexit(manager, None, None, None)

더 자세한 내용은 __aenter__()__aexit__() 를 보면 됩니다.

코루틴 함수의 바디 밖에서 async with 문을 사용하는 것은 SyntaxError 입니다.

더 보기

PEP 492 - async 와 await 문법을 사용하는 코루틴

코루틴을 파이썬에서 적절한 독립적인 개념으로 만들고, 문법 지원을 추가한 제안.

각주

1

다른 예외를 일으키는 finally 절이 있지 않은 한 예외는 호출 스택으로 퍼집니다. 그 새 예외는 예전의 것을 잃어버리게 만듭니다.

2

함수 바디의 첫 번째 문장으로 등장하는 문자열 리터럴은 함수의 __doc__ 어트리뷰트로 변환되어 함수의 독스트링 이 됩니다.

3

클래스 바디의 첫 번째 문장으로 등장하는 문자열 리터럴은 그 이름 공간의 __doc__ 항목으로 변환되어 클래스의 독스트링 이 됩니다.