7. 단순문(Simple statements)

단순문은 하나의 논리적인 줄 안에 구성됩니다. 여러 개의 단순문이 세미콜론으로 분리되어 하나의 줄에 나올 수 있습니다. 단순문의 문법은 이렇습니다:

simple_stmt ::=  expression_stmt
                 | assert_stmt
                 | assignment_stmt
                 | augmented_assignment_stmt
                 | annotated_assignment_stmt
                 | pass_stmt
                 | del_stmt
                 | return_stmt
                 | yield_stmt
                 | raise_stmt
                 | break_stmt
                 | continue_stmt
                 | import_stmt
                 | future_stmt
                 | global_stmt
                 | nonlocal_stmt

7.1. 표현식 문

표현식 문은 값을 계산하고 출력하거나, (보통) 프로시저(procedure) (의미 없는 결과를 돌려주는 함수; 파이썬에서 프로시저는 None 값을 돌려줍니다)를 호출하기 위해 (대부분 대화형으로) 사용됩니다. 표현식 문의 다른 사용도 허락되고 때때로 쓸모가 있습니다.

expression_stmt ::=  starred_expression

표현식 문은 (하나의 표현식일 수 있는) 표현식 목록의 값을 구합니다.

대화형 모드에서, 값이 None 이 아니면, 내장 repr() 함수를 사용해 문자열로 변환되고, 그렇게 나온 문자열을 별도의 줄에 표준 출력으로 보냅니다 (결과가 None 일 때는 그렇지 않아서, 프로시저 호출은 어떤 출력도 만들지 않습니다.),

7.2. 대입문

대입문은 이름을 값에 (재)연결하고 가변 객체의 어트리뷰트나 항목들을 수정합니다.

assignment_stmt ::=  (target_list "=")+ (starred_expression | yield_expression)
target_list     ::=  target ("," target)* [","]
target          ::=  identifier
                     | "(" [target_list] ")"
                     | "[" [target_list] "]"
                     | attributeref
                     | subscription
                     | slicing
                     | "*" target

(attributeref, subscription, slicing 의 문법 정의는 프라이머리 섹션을 보십시오.)

대입문은 표현식 목록 (이것이 하나의 표현식일 수도, 쉼표로 분리된 목록일 수도 있는데, 후자의 경우는 튜플이 만들어진다는 것을 기억하십시오) 의 값을 구하고, 왼쪽에서 오른쪽으로, 하나의 결과 객체를 타깃 목록의 각각에 대입합니다.

대입은 타깃 (목록)의 형태에 따라 재귀적으로 정의됩니다. 타깃이 가변 객체의 일부 (어트리뷰트 참조나 서브스크립션이나 슬라이싱) 면, 가변 객체가 최종적으로 대입을 수행해야만 하고, 그것이 올바른지 아닌지를 결정하고, 대입이 받아들여 질 수 없으면 예외를 일으킬 수 있습니다. 다양한 형들이 주시하는 규칙들과 발생하는 예외들은 그 객체 형의 정의에서 주어진다 (표준형 계층 섹션을 보십시오).

객체를 타깃 목록, 괄호나 대괄호로 둘러싸일 수 있는데 생략할 수 있습니다, 에 대입하는 것은 다음과 같이 재귀적으로 정의됩니다.

  • 타깃 목록이 (선택적으로 괄호에 들어있는) 뒤따르는 쉼표가 없는 하나의 타깃이면 객체는 타깃에 대입됩니다.

  • 그렇지 않으면: 객체는 타깃 목록에 나오는 타깃의 수와 같은 수의 항목들을 제공하는 이터러블이어야 하고, 항목들은, 왼쪽에서 오른쪽으로, 대응하는 타깃들에 대입됩니다.

    • 타깃 목록이 애스터리스크(asterisk)를 앞에 붙인 타깃, "스타드(starred)" 타깃이라고 불립니다, 하나를 포함하면: 객체는 적어도 타깃 목록에 나오는 타깃의 수보다 하나 작은 개수의 항목을 제공하는 이터러블이어야 합니다. 이터러블의 처음 항목들은, 왼쪽에서 오른쪽으로, 스타드 타깃 앞에 나오는 타깃들에 대입됩니다. 이터러블의 마지막 항목들은 스타드 타깃 뒤에 나오는 타깃들에 대입됩니다. 이터러블의 나머지 항목들로 구성된 리스트가 스타드 타깃에 대입됩니다 (이 리스트는 비어있을 수 있습니다).

      flowdas

      • 스타드 타깃은 오직 하나만 사용할 수 있습니다.

      • 스타드 타깃은 아직 연결되지 않은 이름일 수 있습니다.

      • 스타드 타깃은 우변의 객체가 무엇이건, 항상 리스트가 대입됩니다.

      • 우변이 타깃의 수보다 하나 작을 수 있는 이유는, 스타드 타깃에 빈 리스트가 대입될 수 있기 때문입니다.

    • 그렇지 않으면: 객체는 타깃 목록에 나오는 타깃의 수와 같은 수의 항목들을 제공하는 이터러블이어야 하고, 항목들은, 왼쪽에서 오른쪽으로, 대응하는 타깃들에 대입됩니다.

하나의 타깃에 대한 객체의 대입은 다음과 같이 재귀적으로 정의됩니다.

  • 타깃이 식별자 (이름) 면:

    • 그 이름이 현재 코드 블록에 있는 globalnonlocal 문에 등장하지 않으면: 그 이름은 현재 지역 이름 공간에서 객체에 연결됩니다.

    • 그렇지 않으면: 그 이름은 각각 전역 이름 공간이나 nonlocal 에 의해 결정되는 외부 이름 공간에서 객체에 연결됩니다.

    그 이름이 이미 연결되어 있으면 재연결됩니다. 이것은 기존에 연결되어 있던 객체의 참조 횟수가 0이 되도록 만들어서, 객체가 점유하던 메모리가 반납되고 파괴자(destructor) (갖고 있다면) 가 호출되도록 만들 수 있습니다.

  • 타깃이 어트리뷰트 참조면: 참조의 프라이머리 표현식의 값을 구합니다. 이것은 대입 가능한 어트리뷰트를 가진 객체를 주어야 하는데, 그렇지 않으면 TypeError 가 일어납니다. 그에 그 객체에 주어진 어트리뷰트로 객체를 대입하도록 요청합니다; 대입을 수행할 수 없다면 예외 (보통 AttributeError 이지만, 꼭 그럴 필요는 없다) 를 일으킵니다.

    주의 사항: 객체가 클래스 인스턴스이고 어트리뷰트 참조가 대입 연산자의 양쪽에서 모두 등장하면, 우변(right-hand side) 표현식, a.x 는 인스턴스 어트리뷰트나 (인스턴스 어트리뷰트가 없다면) 클래스 어트리뷰트를 액세스할 수 있습니다. 좌변(left-hand side) 타깃 a.x 는 항상 필요하면 만들어서라도 항상 인스턴스 어트리뷰트를 설정합니다. 그래서, 두 a.x 가 같은 어트리뷰트를 가리키는 것은 필요조건이 아닙니다: 우변 표현식이 클래스 어트리뷰트를 가리킨다면, 좌변은 대입의 타깃으로 새 인스턴스 어트리뷰트를 만듭니다:

    class Cls:
        x = 3             # 클래스 변수
    inst = Cls()
    inst.x = inst.x + 1   # inst.x 에 4 를 쓰고 Cls.x 는 3 으로 남겨둡니다
    

    이 설명이 property() 로 만들어진 프로퍼티(property)와 같은 디스크립터 어트리뷰트에 적용될 필요는 없습니다.

    flowdas

    디스크립터 어트리뷰트는 기본적으로 클래스 어트리뷰트인데, 인스턴스를 통해 액세스할 때나 대입할 때 모두 디스크립터의 메서드가 호출됩니다. 이 때 보통 디스크립터는 인스턴스 어트리뷰트를 만들지 않습니다.

  • 타깃이 서브스크립션이면: 참조에 있는 프라이머리 표현식의 값을 구합니다. (리스트 같은) 가변 시퀀스 객체나 (딕셔너리 같은) 매핑 객체가 나와야 합니다. 그런 다음, 서브 스크립트 표현식의 값을 구합니다.

    프라이머리가 (리스트 같은) 가변 시퀀스 객체면, 서브 스크립트는 정수가 나와야 합니다. 음수면, 시퀀스의 길이가 더해집니다. 결괏값은 시퀀스의 길이보다 작은 음이 아닌 정수여야 하고, 시퀀스에 그 인덱스를 가진 항목에 객체를 대입하라고 요청합니다. 인덱스가 범위를 벗어나면, IndexError 를 일으킵니다 (서브 스크립트 된 시퀀스에 대한 대입은 리스트에 새 항목을 추가할 수 없습니다).

    프라이머리가 (딕셔너리 같은) 매핑 객체면, 서브 스크립트는 매핑의 키 형과 호환되는 형이어야 하고, 매핑에 그 서브 스크립트를 객체에 매핑하는 키/데이터 쌍을 만들도록 요청합니다. 이때 같은 킷값을 갖는 기존의 키/값 쌍을 대체할 수도 있고, (같은 값의 키가 존재하지 않는 경우) 새 키/값 쌍을 삽입할 수도 있습니다.

    사용자 정의 객체의 경우는, 적절한 인자로 __setitem__() 메서드가 호출됩니다.

  • 타깃이 슬라이싱이면: 참조의 프라이머리 표현식의 값을 구합니다. (리스트 같은) 가변 시퀀스 객체가 나와야 합니다. 대입되는 객체는 같은 형의 시퀀스 객체야 합니다. 그런 다음, 존재한다면 하한과 상한 표현식의 값을 구합니다; 기본값은 0과 시퀀스의 길이다. 경곗값은 정수가 되어야 합니다. 둘 중 어느 것이건 음수가 나오면, 시퀀스의 길이를 더합니다. 그렇게 얻어진 경곗값들을 0과 시퀀스의 길이나 그 사이에 들어가는 값이 되도록 자릅니다. 마지막으로 시퀀스 객체에 슬라이스를 대입되는 시퀀스로 변경하도록 요청합니다. 타깃 시퀀스가 허락한다면, 슬라이스의 길이는 대입되는 시퀀스의 길이와 다를 수 있습니다.

    flowdas

    대입되는 객체가 타깃과 같은 형의 시퀀스일 필요는 없습니다. 이터러블이기만 하면 됩니다.

    flowdas

    “경곗값들을 0과 시퀀스의 길이나 그 사이에 들어가는 값이 되도록 자릅니다” 의 뜻은, 하한 값이 0 보다 작으면 0 으로 바꾸고, 상한 값이 시퀀스의 길이보다 크다면 시퀀스의 길이로 바꾼다는 뜻입니다. 이는 정수 서브스크립트를 다루는 방식과 약간 달라보일 수 있습니다. 가령 길이 10 인 시퀀스 a 가 있을 때 a[-11] 이나 a[11]IndexError 를 일으키는 반면, a[-11:11]a[0:10] 과 같게 취급됩니다. 음수값을 경계로 사용할 때는, 이렇게 자르기 전에 시퀀스의 길이를 더하는 것을 먼저 수행합니다. 따라서 a[-1:11]a[0:10] 이 아니라 a[9:10] 으로 해석됩니다.

CPython implementation detail: 현재 구현에서, 타깃의 문법은 표현식과 같게 유지되고, 잘못된 문법은 코드 생성 단계에서 거부되기 때문에 에러 메시지가 덜 상세해지는 결과를 낳고 있습니다.

설사 대입의 정의가 좌변과 우변 간의 중첩이 '동시적(simultaneous)'임을 (예를 들어, a, b = b, a 는 두 변수를 교환합니다) 암시해도, 대입되는 변수들의 컬렉션 에서의 중첩은 왼쪽에서 오른쪽으로 일어나서, 때로 혼동할 수 있는 결과를 낳습니다. 예를 들어, 다음과 같은 프로그램은 [0, 2] 를 인쇄합니다:

x = [0, 1]
i = 0
i, x[i] = 1, 2         # i 가 갱신된 다음에, x[i] 가 갱신됩니다
print(x)

더 보기

PEP 3132 - 확장 이터러블 언 패킹

*target 기능에 대한 규격

7.2.1. 증분 대입문(Augmented assignment statements)

증분 대입문은 한 문장에서 이항 연산과 대입문을 합치는 것입니다:

augmented_assignment_stmt ::=  augtarget augop (expression_list | yield_expression)
augtarget                 ::=  identifier | attributeref | subscription | slicing
augop                     ::=  "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**="
                               | ">>=" | "<<=" | "&=" | "^=" | "|="

(마지막 세 기호의 문법 정의는 프라이머리 섹션을 보십시오.)

flowdas

"마지막 세 기호" 는 attributeref, subscription, slicing 를 뜻합니다.

증분 대입은 타깃 (일반 대입문과는 달리 언 패킹이 될 수 없습니다) 과 표현식 목록의 값을 구하고, 둘을 피연산자로 삼아 대입의 형에 맞는 이항 연산을 수행한 후, 원래의 타깃에 그 결과를 대입합니다. 타깃은 오직 한 번만 값이 구해집니다.

x += 1 과 같은 증분 대입 표현은 x = x + 1 처럼 다시 쓸 수 있는데, 정확히 같은 효과는 아니지만 비슷한 결과를 줍니다. 증분 버전에서는, x 의 값을 오직 한 번만 구합니다. 또한, 가능할 때, 실제 연산은 제자리(in-place) 에서 수행되는데, 새 객체를 만들고 그것을 타깃에 대입하기보다는, 예전 객체를 수정한다는 의미입니다.

일반 대입과는 달리, 증분 대입은 우변의 값을 구하기 이전에 좌변의 값을 구합니다. 예를 들어, a[i] += f(x) 는 처음에 a[i] 를 조회한 다음, f(x) 의 값을 구하고, 덧셈을 수행하고, 마지막으로 그 결과를 a[i] 에 다시 씁니다.

하나의 문장에서 튜플과 다중 타깃으로 대입하는 것을 예외로 하면, 증분 대입문에 의한 대입은 일반 대입과 같은 방법으로 처리됩니다. 마찬가지로, 제자리 동작의 가능성을 예외로 하면, 증분 대입 때문에 수행되는 이진 연산은 일반 이진 연산과 같습니다.

어트리뷰트 참조인 타깃의 경우, 일반 대입처럼 클래스와 인스턴스 어트리뷰트에 관한 경고 가 적용됩니다.

7.2.2. 어노테이트된 대입문(Annotated assignment statements)

어노테이션 대입은, 한 문장에서, 변수나 어트리뷰트 어노테이션과 생략할 수 있는 대입문을 합치는 것입니다.

annotated_assignment_stmt ::=  augtarget ":" expression
                               ["=" (starred_expression | yield_expression)]

일반 대입문 과의 차이점은 오직 하나의 타깃만 허락된다는 것입니다.

대인 타깃에 단순한 이름을 쓰는 경우, 클래스나 모듈 스코프에 있으면, 어노테이션은 값이 구해진 후 특별한 클래스나 모듈의 어트리뷰트 __annotations__ 에 저장되는데, 이 어트리뷰트는 (만약 비공개면 뒤섞인) 변수 이름을 어노테이션의 값으로 대응시키는 딕셔너리 매핑입니다. 이 어트리뷰트는 쓰기가 허락되고, 클래스나 모듈의 실행을 시작할 때 어노테이션이 정적으로 발견되면 만들어집니다.

대입 타깃으로 표현식을 쓸 때, 어노테이션은 클래스나 모듈 스코프에 있는 것처럼 값이 구해지지만 저장되지는 않습니다.

이름이 함수 스코프에서 어노테이트되면, 이 이름은 그 스코프에 지역적(local)입니다. 함수 스코프에서 어노테이션은 값이 구해지거나 저장되지 않습니다.

flowdas

함수 스코프에서 우변을 생략하고 단순히 어노테이션만 하면, 지역 변수의 선언과 같은 효과를 줍니다.

우변이 존재하면, 어노테이트된 대입은 (적절한 곳에서) 어노테이션의 값을 구하기 전에 실제 대입을 수행합니다. 표현식 타깃의 경우 우변이 존재하지 않으면, 인터프리터는 티깃의 값을 구하는데, 마지막 __setitem__() 이나 __setattr__() 호출은 생략합니다.

더 보기

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

주석을 통해 표현하는 대신, 변수(클래스 변수와 인스턴스 변수 포함)의 형을 어노테이트 하는 문법을 추가하는 제안.

PEP 484 - 형 힌트

정적 분석 도구와 IDE에서 사용할 수 있는 형 어노테이션에 대한 표준 문법을 제공하기 위해 typing 모듈을 추가하는 제안.

버전 3.8에서 변경: 이제 어노테이트된 대입문은 일반 대입과 마찬가지로 우변에 같은 표현식을 허용합니다. 이전에는, (괄호 없는 튜플 표현식과 같은) 일부 표현식에서 문법 에러가 발생했습니다.

7.3. assert

assert 문은 프로그램에 디버깅 어서션(debugging assertion)을 삽입하는 편리한 방법입니다:

assert_stmt ::=  "assert" expression ["," expression]

간단한 형태, assert expression 은 다음과 동등합니다

if __debug__:
    if not expression: raise AssertionError

확장된 형태, assert expression1, expression2 는 다음과 동등합니다

if __debug__:
    if not expression1: raise AssertionError(expression2)

이 동등성 들은 __debug__AssertionError 가 같은 이름의 내장 변수들을 가리킨다고 가정합니다. 현재 구현에서, 내장 변수 __debug__ 은 일반적인 상황에서 True 이고, 최적화가 요청되었을 때 (명령행 옵션 -O) False 입니다. 현재의 코드 생성기는 컴파일 시점에 최적화가 요청되면 assert 문을 위한 코드를 만들지 않습니다. 에러 메시지에 실패한 표현식의 소스 코드를 포함할 필요가 없음에 주의하십시오; 그것은 스택 트레이스의 일부로 출력됩니다.

__debug__ 에 대한 대입은 허락되지 않습니다. 이 내장 변수의 값은 인터프리터가 시작할 때 결정됩니다.

flowdas

builtins.__debug__ = False 를 하면 SyntaxError 가 발생합니다. 키워드로 대입하려 한다는 에러 메시지가 나오는데, 그냥 하는 소리고 __debug__ 이 키워드는 아닙니다.

7.4. pass

pass_stmt ::=  "pass"

pass 는 널(null) 연산입니다 --- 실행될 때, 아무런 일도 일어나지 않습니다. 문법적으로 문장이 필요하기는 하지만 할 일은 없을 때, 자리를 채우는 용도로 쓸모가 있습니다, 예를 들어:

def f(arg): pass    # (아직은) 아무것도 하지 않는 함수

class C: pass       # (아직은) 메서드가 없는 클래스

7.5. del

del_stmt ::=  "del" target_list

삭제는 대입이 정의된 방식과 아주 비슷하게 재귀적으로 정의됩니다. 전체 세부 사항들을 나열하는 대신, 여기 몇 가지 힌트가 있습니다.

타깃 목록의 삭제는 각 타깃을 왼쪽에서 오른쪽으로 재귀적으로 삭제합니다.

이름의 삭제는 같은 코드 블록에 있는 global 문에 그 이름이 등장하는지에 따라 지역이나 전역 이름 공간에서 이름의 연결을 제거합니다. 이름이 연결되어 있지 않으면, NameError 예외가 일어납니다.

어트리뷰트 참조, 서브스크립션, 슬라이싱의 삭제는 관련된 프라이머리 객체로 전달됩니다; 슬라이싱의 삭제는 일반적으로 우변 형의 빈 슬라이스를 대입하는 것과 동등합니다 (하지만 이것조차 슬라이싱 되는 객체가 판단합니다).

버전 3.2에서 변경: 예전에는 이름이 중첩된 블록에서 자유 변수로 등장하는 경우 지역 이름 공간에서 삭제하는 것이 허락되지 않았습니다.

7.6. return

return_stmt ::=  "return" [expression_list]

return 은 문법적으로 클래스 정의에 중첩된 경우가 아니라, 함수 정의에만 중첩되어 나타날 수 있습니다.

flowdas

함수 정의 에서만 return 문을 사용할 수 있다는 뜻입니다. 클래스 정의의 문법 규칙을 보면 그런 제약을 표현하고 있지 않기 때문에 덧붙이는 말입니다.

표현식 목록이 있으면 값을 구하고, 그렇지 않으면 None 으로 치환됩니다.

return 은 표현식 목록 (또는 None)을 반환 값으로 해서, 현재의 함수 호출을 떠납니다.

returnfinally 절을 가진 try 문에서 제어가 벗어나도록 만드는 경우, 함수로부터 진짜로 벗어나기 전에 그 finally 절이 실행됩니다.

제너레이터 함수에서, return 문은 제너레이터가 끝났음을 가리키고, StopIteration 예외를 일으킵니다. return 문에 제공되는 값은 (있다면) StopIteration 의 생성자에 인자로 전달되어 StopIteration.value 어트리뷰트가 됩니다.

비동기 제너레이터 함수에서, 빈 return 문은 비동기 제너레이터가 끝났음을 알리고, StopAsyncIteration 예외를 일으킵니다. 비동기 제너레이터 함수에서, 비어있지 않은 return 은 문법 에러입니다.

7.7. yield

yield_stmt ::=  yield_expression

yield 문은 yield 표현식 과 같은 의미가 있습니다. 동등한 yield 표현식에서 필요로 하는 괄호를 생략하기 위해 yield 문을 사용합니다. 예를 들어, yield 문

yield <expr>
yield from <expr>

은 다음과 같은 yield 표현식 문장들과 동등합니다

(yield <expr>)
(yield from <expr>)

yield 표현식과 문장은 제너레이터 함수를 정의할 때만 사용되고, 제너레이터 함수의 바디에서만 사용됩니다. 함수 정의가 일반 함수 대신 제너레이터 함수를 만들도록 하는 데는 yield를 사용하는 것만으로 충분합니다.

yield 의 뜻에 대한 전체 세부 사항들은 일드 표현식(Yield expressions) 섹션을 참고하면 됩니다.

7.8. raise

raise_stmt ::=  "raise" [expression ["from" expression]]

표현식이 주어지지 않으면, raise 는 현재 스코프에서 활성화된 마지막 예외를 다시 일으킵니다. 현재 스코프에 활성화된 예외가 없다면, 이것이 에러라는 것을 알리기 위해 RuntimeError 예외를 일으킵니다.

그렇지 않으면, raise 는 예외 객체로, 첫 번째 표현식의 값을 구합니다. BaseException 의 서브 클래스나 인스턴스여야 합니다. 클래스면, 예외 인스턴스는 필요할 때 인자 없이 클래스의 인스턴스를 만들어서 사용됩니다.

예외의 형(type)은 예외 인스턴스의 클래스고, 값(value)은 인스턴스 자신입니다.

트레이스백 객체는 보통 예외가 일어날 때 자동으로 만들어지고 쓰기 가능한 __traceback__ 어트리뷰트로 첨부됩니다. 다음과 같이, with_traceback() 예외 메서드를 사용하면, 예외를 만들고 트레이스백을 직접 설정하는 것을 한 번에 할 수 있습니다 (같은 예외 인스턴스를 돌려주는데, 그 인자값으로 트레이스백을 설정해줍니다):

raise Exception("foo occurred").with_traceback(tracebackobj)

from 절은 예외 연쇄(exception chaining)에 사용됩니다. 주어진다면, 두 번째 표현식(expression) 은 또 하나의 예외 클래스나 인스턴스야 되는데, 발생한 예외에 (쓰기 가능한) __cause__ 어트리뷰트로 첨부됩니다. 발생한 예외가 처리되지 않으면, 두 예외가 모두 인쇄됩니다:

>>> try:
...     print(1 / 0)
... except Exception as exc:
...     raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

예외 처리기나 finally 절에서 예외가 발생하면 비슷한 메커니즘이 묵시적으로 적용됩니다: 앞선 예외가 새 예외의 __context__ 어트리뷰트로 첨부됩니다.

>>> try:
...     print(1 / 0)
... except:
...     raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

예외 연쇄는 from 절에 None 을 지정해서 명시적으로 중지시킬 수 있습니다:

>>> try:
...     print(1 / 0)
... except:
...     raise RuntimeError("Something bad happened") from None
...
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

예외에 대한 더 많은 정보를 예외 섹션에서 발견할 수 있고, 예외를 처리하는 것에 대한 정보는 try 문 섹션에 있습니다.

버전 3.3에서 변경: 이제 raise X from Y 에서 YNone 이 허락됩니다.

버전 3.3에 추가: 예외 문맥(exception context)의 자동 출력을 제한할 수 있는 __suppress_context__ 어트리뷰트

flowdas

예외 문맥이란 예외 인스턴스에 __context__ 어트리뷰트로 제공되는 예외 인스턴스를 뜻하는데, __cause__ 와 비슷한 역할을 합니다. 차이점은 __cause__ 의 경우 None 으로 설정할 수 있지만, __context__ 의 경우는 그렇지 않다는 것입니다. 보통 from 절을 사용해서 __cause__ 를 설정하면 __suppress_context__True 로 설정합니다. __cause__ 는 예외를 출력하는데 사용되고, __context__ 는 인트로스펙션에 사용됩니다.

7.9. break

break_stmt ::=  "break"

break 는 문법적으로 forwhile 루프에 중첩되어서만 나타날 수 있습니다. 하지만 그 루프 안의 함수나 클래스 정의에 중첩되지는 않습니다.

가장 가까이서 둘러싸고 있는 루프를 종료하고, 그 루프가 else 절을 갖고 있다면 건너뜁니다(skip).

for 루프가 break 로 종료되면, 루프 제어 타깃은 현재값을 유지합니다.

breakfinally 절을 가 try 문에서 제어가 벗어나도록 만드는 경우, 루프로부터 진짜로 벗어나기 전에 그 finally 절이 실행됩니다.

7.10. continue

continue_stmt ::=  "continue"

continue 는 문법적으로 forwhile 루프에 중첩되어서만 나타날 수 있습니다. 하지만 그 루프 안의 함수나 클래스 정의에 중첩되지는 않습니다. 가장 가까이서 둘러싸고 있는 루프가 다음 사이클로 넘어가도록 만듭니다.

continuefinally 절을 가진 try 문에서 제어가 벗어나도록 만드는 경우, 다음 루트 사이클을 시작하기 전에 그 finally 절이 실행됩니다.

7.11. 임포트(import) 문

import_stmt     ::=  "import" module ["as" identifier] ("," module ["as" identifier])*
                     | "from" relative_module "import" identifier ["as" identifier]
                     ("," identifier ["as" identifier])*
                     | "from" relative_module "import" "(" identifier ["as" identifier]
                     ("," identifier ["as" identifier])* [","] ")"
                     | "from" module "import" "*"
module          ::=  (identifier ".")* identifier
relative_module ::=  "."* module | "."+

(from 절이 없는) 기본 임포트 문은 두 단계로 실행됩니다:

  1. 모듈을 찾고, 로드하고, 필요하면 초기화합니다

  2. 임포트(import) 문이 등장한 스코프의 지역 이름 공간에 이름이나 이름들을 정의합니다.

문장이 (쉼표로 분리된) 여러 개의 절을 포함하면, 마치 각 절이 별도의 임포트 문에 의해 분리된 것처럼, 두 단계는 절마다 별도로 수행됩니다.

첫 번째 단계, 모듈을 찾고 로드하는 것의 세부 사항은 임포트 시스템 에 있는 섹션에서 아주 상세하게 설명하는데, 임포트될 수 있는 여러 종류의 패키지와 모듈들과 임포트 시스템을 커스터마이즈하는데 사용될 수 있는 모든 훅에 관해서도 설명하고 있습니다.

요청된 모듈이 성공적으로 읽어 들여지면, 세 가지 중 한 방법으로 지역 이름 공간에 소개됩니다:

  • 모듈 이름 뒤에 as 가 오면, as 뒤에 오는 이름이 임포트된 모듈에 직접 연결됩니다.

  • 다른 이름이 지정되지 않고, 임포트되는 모듈이 최상위 모듈이면, 모듈의 이름이 임포트되는 모듈에 대한 참조로 지역 이름 공간에 연결됩니다.

  • 임포트되는 모듈이 최상이 모듈이 아니 라면, 그 모듈을 포함하는 최상위 패키지의 이름이 최상위 패키지에 대한 참조로 지역 이름 공간에 연결됩니다. 임포트된 모듈은 직접적이기보다는 완전히 정규화된 이름(full qualified name)을 통해 액세스 되어야 합니다.

from 형은 약간 더 복잡한 절차를 사용합니다:

  1. from 절에 지정된 모듈을 찾고, 로드하고, 필요하면 초기화합니다

  2. import 절에 지정된 식별자들 각각에 대해:

    1. 임포트된 모듈이 그 이름의 어트리뷰트를 가졌는지 검사합니다

    2. 없으면, 그 이름의 서브 모듈을 임포트하는 것을 시도한 다음 임포트된 모듈에서 그 어트리뷰트를 다시 검사합니다

    3. 어트리뷰트가 발견되지 않으면 ImportError 를 일으킵니다.

    4. 그렇지 않으면, 그 값에 대한 참조가 지역 이름 공간에 저장되는데, as 절이 존재하면 거기에서 지정된 이름을 사용하고, 그렇지 않으면 어트리뷰트 이름을 사용합니다

사용 예:

import foo                 # foo 가 임포트되고 지역적으로 연결됩니다
import foo.bar.baz         # foo.bar.baz 가 임포트되고, foo 가 지역적으로 연결됩니다
import foo.bar.baz as fbb  # foo.bar.baz 가 임포트되고 fbb 로 연결됩니다
from foo.bar import baz    # foo.bar.baz 가 임포트되고 baz 로 연결됩니다
from foo import attr       # foo 가 임포트되고 foo.attr 이 attr 로 연결됩니다

식별자들의 목록을 스타 ('*') 로 바꾸면, 모듈에 정의된 모든 공개 이름들이 import 문이 등장한 스코프의 지역 이름 공간에 연결됩니다.

모듈에 정의된 공개 이름(public names) 은 모듈의 이름 공간에서 __all__ 이라는 이름의 변수를 검사해서 결정됩니다; 정의되어 있다면, 문자열의 시퀀스여야 하는데, 그 모듈이 정의하거나 임포트하는 이름들입니다. __all__ 에서 지정한 이름들은 모두 공개로 취급되고 반드시 존재해야 합니다. __all__ 이 정의되지 않으면, 모듈의 이름 공간에서 발견되는 이름 중, 밑줄 문자 ('_')로 시작하지 않는 모든 이름이 공개로 취급됩니다. __all__ 는 공개 API 전체를 포함해야 합니다. 이것의 목적은 의도치 않게 API 일부가 아닌 항목들을 노출하는 것을 방지하는 것입니다 (가령 그 모듈이 임포트하고 사용하는 라이브러리 모듈).

임포트의 와일드카드 형태 --- from module import * --- 는 모듈 수준에서만 허락됩니다. 클래스나 함수 정의에서 사용하려는 시도는 SyntaxError 를 일으킵니다.

임포트할 모듈을 지정할 때 모듈의 절대 이름(absolute name)을 지정할 필요는 없습니다. 모듈이나 패키지가 다른 패키지 안에 포함될 때, 같은 상위 패키지 내에서는 그 패키지 이름을 언급할 필요 없이 상대 임포트(relative import)를 할 수 있습니다. from 뒤에 지정되는 패키지나 모듈 앞에 붙이는 점으로, 정확한 이름을 지정하지 않고도 현재 패키지 계층을 얼마나 거슬러 올라가야 하는지 지정할 수 있습니다. 하나의 점은 이 임포트를 하는 모듈이 존재하는 현재 패키지를 뜻합니다. 두 개의 점은 한 패키지 수준을 거슬러 올라가는 것을 뜻합니다. 세 개의 점은 두 개의 수준을, 등등입니다. 그래서 pkg 패키지에 있는 모듈에서 from . import mod 를 실행하면, pkg.mod 를 임포트하게 됩니다. pkg.subpkg1 안에서 from ..subpkg2 import mod 를 실행하면 pkg.subpkg2.mod 를 임포트하게 됩니다. 상대 임포트에 대한 규격은 패키지 상대 임포트 절에 들어있습니다.

로드할 모듈들을 동적으로 결정하는 응용 프로그램들을 지원하기 위해 importlib.import_module() 이 제공됩니다.

인자 module, filename, sys.path, sys.meta_path, sys.path_hooks감사 이벤트 import를 발생시킵니다.

7.11.1. 퓨처 문

퓨처 문(future statement)은 컴파일러가 특정한 모듈을 특별한 문법이나 개념을 사용해서 컴파일하도록 만드는 지시어(directive)인데, 그 기능은 미래에 출시되는 파이썬에서 표준이 되는 것입니다.

퓨처 문의 목적은 언어에 호환되지 않는 변경이 도입된 미래 버전의 파이썬으로 옮겨가는 것을 쉽게 만드는 것입니다. 그 기능이 표준이 되는 배포 이전에 모듈 단위로 새 기능을 사용할 수 있도록 만듭니다.

future_stmt ::=  "from" "__future__" "import" feature ["as" identifier]
                 ("," feature ["as" identifier])*
                 | "from" "__future__" "import" "(" feature ["as" identifier]
                 ("," feature ["as" identifier])* [","] ")"
feature     ::=  identifier

퓨처 문은 모듈의 거의 처음에 나와야 합니다. 퓨처 문 앞에 나올 수 있는 줄들은:

  • 모듈 독스트링(docstring) (있다면),

  • 주석

  • 빈 줄, 그리고

  • 다른 퓨처 문들

파이썬 3.7에서 퓨처 문을 사용해야 하는 유일한 기능은 annotations 입니다.

과거에 퓨처 문을 통해 활성화되던 기능들은 여전히 파이썬 3에 의해 인식됩니다. 이 목록에는 absolute_import, division, generators, generator_stop, unicode_literals, print_function, nested_scopeswith_statement 가 포함됩니다. 이것들은 잉여물인데 항상 활성화되고, 오직 과거 호환성을 위해 유지되고 있기 때문입니다.

퓨처 문은 구체적으로는 컴파일 시점에 인식되고 다뤄집니다: 핵심 구성물들의 의미에 대한 변경은 종종 다른 코드 생성을 통해 구현됩니다. 새 기능이 호환되지 않는 (새로운 예약어처럼) 새로운 문법을 도입하는 경우조차 가능한데, 이 경우는 컴파일러가 모듈을 다르게 파싱할 수 있습니다. 그런 결정들은 실행 시점으로 미뤄질 수 없습니다..

배포마다, 컴파일러는 어떤 기능 이름들이 정의되어 있는지 알고, 만약 퓨처 문이 알지 못하는 기능을 포함하고 있으면 컴파일 시점 에러를 일으킵니다.

직접적인 실행 시점의 개념은 다른 임포트 문들과 같습니다: 표준 모듈 __future__, 후에 설명합니다, 다 있고, 퓨처 문이 실행되는 시점에 일반적인 방법으로 임포트됩니다.

흥미로운 실행 시점의 개념들은 퓨처 문에 의해 활성화되는 구체적인 기능들에 달려있습니다.

이런 문장에는 아무것도 특별한 것이 없음에 주의해야 합니다:

import __future__ [as name]

이것은 퓨처 문이 아닙니다; 아무런 특별한 개념이나 문법적인 제약이 없는 평범한 임포트 문일 뿐입니다.

퓨처 문을 포함하는 모듈 M 에 등장하는 내장 함수 exec()compile() 를 호출해서 컴파일되는 코드는, 기본적으로는, 퓨처 문이 지정하는 새 문법과 개념을 사용합니다. 이것은 compile() 에 주는 생략 가능한 인자로 제어될 수 있습니다 --- 자세한 내용은 그 함수의 문서를 보십시오.

대화형 인터프리터 프롬프트에서 입력된 퓨처 문은 인터프리터 세션의 남은 기간 효과를 발생시킵니다. 인터프리터가 -i, 실행할 스크립트 이름이 전달됩니다, 옵션으로 시작하고, 그 스크립트가 퓨처 문을 포함하면, 스크립트가 실행된 이후에 시작되는 대화형 세션에서도 효과를 유지합니다.

더 보기

PEP 236 - 백 투 더 __future__

__future__ 메커니즘에 대한 최초의 제안.

7.12. global

global_stmt ::=  "global" identifier ("," identifier)*

global 문은 현재 코드 블록 전체에 적용되는 선언입니다. 나열된 식별자들이 전역으로 해석되어야 한다는 뜻입니다. global 선언 없이 자유 변수들이 전역을 가리킬 수 있기는 하지만, global 없이 전역 변수에 값을 대입하는 것은 불가능합니다.

global 문에 나열된 이름들은 같은 코드 블록에서 global 문 앞에 등장할 수 없습니다.

global 문에 나열된 이름들은 형식 매개변수나 for 루프 제어 타깃, 클래스(class) 정의, 함수 정의, 임포트(import) 문, 변수 어노테이션으로 정의되지 않아야 합니다.

CPython implementation detail: 현재 구현이 이 제약들의 일부를 강제하지 않지만, 프로그램은 이 자유를 남용하지 말아야 하는데, 미래의 구현은 그것들을 강제하거나 프로그램의 의미를 예고 없이 변경할 수 있기 때문입니다.

프로그래머의 주의 사향: global 은 파서에 주는 지시자(directive)입니다. global 문과 같은 시점에 파싱되는 코드에만 적용됩니다. 특히, 내장 exec() 함수로 공급되는 문자열이나 코드 객체에 포함된 global 문은 그 함수 호출을 포함하는 코드 블록에는 영향을 주지 않고, 그런 문자열에 포함된 코드 역시 함수 호출을 포함하는 코드에 있는 global 문에 영향을 받지 않습니다. eval()compile() 함수들도 마찬가지입니다.

7.13. nonlocal

nonlocal_stmt ::=  "nonlocal" identifier ("," identifier)*

nonlocal 문은 나열된 식별자들이 전역을 제외하고 가장 가까이서 둘러싸는 스코프에서 이미 연결된 변수를 가리키도록 만듭니다. 이것은 중요한데, 연결의 기본 동작이 지역 이름 공간을 먼저 검색하는 것이기 때문입니다. 이 문장은 캡슐화된 코드가 전역 (모듈) 스코프 외에 지역 스코프 밖의 변수들에 재연결할 수 있도록 합니다.

nonlocal 문에 나열된 이름들은, global 문에 나열된 것들과는 달리, 둘러싼 스코프에서 이미 존재하는 연결들을 가리켜야만 합니다 (새 연결이 어떤 스코프에 만들어져야만 하는지 명확하게 결정할 수 없습니다).

nonlocal 문에 나열되는 이름들은 지역 스코프에 이미 존재하는 연결들과 겹치지 않아야 합니다.

더 보기

PEP 3104 - 바깥 스코프에 있는 이름들에 대한 액세스

nonlocal 문의 규격.