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〉 문제를 해결한다).

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

8.1. if

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

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

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

8.2. while

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

while_stmt ::=  "while" 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             # this will not affect the for-loop
                      # because i will be overwritten with the next
                      # index in the range

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

참고

There is a subtlety when the sequence is being modified by the loop (this can only occur for mutable sequences, e.g. lists). An internal counter is used to keep track of which item is used next, and this is incremented on each iteration. When this counter has reached the length of the sequence the loop terminates. This means that if the suite deletes the current (or a previous) item from the sequence, the next item will be skipped (since it gets the index of the current item which has already been treated). Likewise, if the suite inserts an item in the sequence before the current item, the current item will be treated again the next time through the loop. This can lead to nasty bugs that can be avoided by making a temporary copy using a slice of the whole sequence, e.g.,

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

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() 값들은 예외를 처리한 함수로부터 복귀할 때 이전 값으로 복구된다.

The optional else clause is executed if the control flow leaves the try suite, no exception was raised, and no return, continue, or break statement was executed. Exceptions in the else clause are not handled by the preceding except clauses.

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

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

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

tryfinally 문의 try 스위트에서 return, break, continue 문이 실행될 때, finally 절도 〈나가는 길에〉 실행된다. finally 절에서는 continue 문을 사용할 수 없다. (그 이유는 현재 구현에 있는 문제 때문이다 — 이 제약은 미래에 제거될 수 있다).

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

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

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

8.5. with

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

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

하나의 《item》 을 사용하는 with 문의 실행은 다음과 같이 진행된다:

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

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

  3. 컨텍스트 관리자의 __enter__() 메서드를 호출한다.

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

    참고

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

  5. 스위트가 실행된다.

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

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

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

하나 보다 많은 항목을 주면, 컨텍스트 관리자는 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               ::=  "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE
dotted_name             ::=  identifier ("." identifier)*
parameter_list          ::=  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 에 연결되지 않는다는 점만 다르다.

하나나 그 이상의 파라미터 들이 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》 뒤에 오는 파라미터들은 키워드 전용 파라미터들이고, 키워드 인자로만 전달될 수 있다.

파라미터들은 파라미터 이름 뒤에 오는 《: expression》 형태의 어노테이션을 가질 수 있다. 모든 파라미터는 어노테이션을 가질 수 있는데, *identifier**identifier 형태조차 그렇다. 함수는 파라미터 목록 뒤에 오는 《-> expression》 형태의 반환(《return》) 어노테이션을 가질 수 있다. 이 어노테이션들은 올바른 파이썬 표현식이면 어떤 것이건 될 수 있고, 함수 정의가 실행될 때 값이 구해진다. 어노테이션은 소스 코드에 등장하는 것과 다른 순서로 값이 구해질 수 있다. 어노테이션의 존재는 함수의 의미를 바꾸지 않는다. 어노테이션 값들은 함수 객체의 __annotations__ 어트리뷰트에서 파라미터의 이름을 키로 하는 딕셔너리의 값으로 제공된다.

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

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

더 보기

PEP 3107 - 함수 어노테이션

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

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__ 에 보존된다. 이것은 클래스가 만들어진 직후에, 정의 문법을 사용해서 정의되는 클래스들에서만 신뢰할 수 있다는 것에 주의해야 한다.

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

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

@f1(arg)
@f2
class Foo: pass

는 대략 다음과 동등하다

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

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

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

더 보기

PEP 3115 - Metaclasses in Python 3000

The proposal that changed the declaration of metaclasses to the current syntax, and the semantics for how classes with metaclasses are constructed.

PEP 3129 - Class Decorators

The proposal that added class decorators. Function and method decorators were introduced in 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 는 코루틴 바디에서만 사용할 수 있다.

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

async def 코루틴에서 yield from 표현식을 사용하는 것은 SyntaxError 다.

코루틴 함수의 예:

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

8.8.2. async for

async_for_stmt ::=  "async" for_stmt

비동기 이터러블iter 구현에서 비동기 코드를 호출할 수 있고, 비동기 이터레이터next 메서드에서 비동기 코드를 호출할 수 있다.

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

다음과 같은 코드는:

async for TARGET in ITER:
    BLOCK
else:
    BLOCK2

의미상으로 다음과 동등하다:

iter = (ITER)
iter = type(iter).__aiter__(iter)
running = True
while running:
    try:
        TARGET = await type(iter).__anext__(iter)
    except StopAsyncIteration:
        running = False
    else:
        BLOCK
else:
    BLOCK2

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

async def 함수 밖에서 async for 문을 사용하는 것은 SyntaxError 다.

8.8.3. async with

async_with_stmt ::=  "async" with_stmt

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

다음과 같은 코드는:

async with EXPR as VAR:
    BLOCK

의미상으로 다음과 동등하다:

mgr = (EXPR)
aexit = type(mgr).__aexit__
aenter = type(mgr).__aenter__(mgr)

VAR = await aenter
try:
    BLOCK
except:
    if not await aexit(mgr, *sys.exc_info()):
        raise
else:
    await aexit(mgr, None, None, None)

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

async def 함수 밖에서 async with 문을 사용하는 것은 SyntaxError 다.

더 보기

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

The proposal that made coroutines a proper standalone concept in Python, and added supporting syntax.

각주

1

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

2

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

3

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