Python

6. 표현식

이 장은 파이썬에서 사용되는 표현식 요소들의 의미를 설명합니다.

문법 유의 사항: 이 장과 다음 장에서는 어휘 분석이 아닌 문법을 설명하기 위해 문법 표기법 을 사용합니다.

문법 규칙의 (어느 한 대안이) 다음과 같은 형태일 때:

name: othername

뜻(semantics)을 주지 않으면, 이 형태의 name 의 뜻은 othername 과 같습니다.

6.1. 산술 변환

아래 산술 연산자 설명에서 “수치 인수가 공통의 실수 타입으로 변환된다”는 문구가 사용된 경우, 이는 내장 수치 타입에 대한 연산자 구현이 표준 라이브러리 문서의 Numeric Types 섹션에 기술된 대로 작동함을 의미합니다.

특정 연산자와 비수치 피연산자(예를 들어, % 연산자의 왼쪽 인자로 사용된 문자열)에 대해서는 몇 가지 추가 규칙이 적용됩니다. 확장 모듈은 자체적인 변환 동작을 정의해야 합니다.

6.2. 아톰 (Atoms)

아톰은 표현식의 가장 기본적인 요소입니다. 가장 간단한 아톰은 내장 상수, 이름, 그리고 리터럴 입니다. 더 복잡한 아톰은 쌍을 이루는 구분자로 둘러싸여 있습니다.

공식적으로 아톰의 문법은 다음과 같습니다.

atom:
   | builtin_constant
   | identifier
   | literal
   | parenthesized_enclosure
   | bracketed_enclosure
   | braced_enclosure
parenthesized_enclosure:
   | group
   | tuple
   | yield_atom
   | generator_expression
bracketed_enclosure:
   | listcomp
   | list
braced_enclosure:
   | dictcomp
   | dict
   | setcomp
   | set

6.2.1. 내장 상수

키워드 True, False, 그리고 None내장 상수 의 이름을 나타냅니다. 토큰 ...Ellipsis 상수의 이름을 나타냅니다.

이 아톰들을 평가하면 해당 값이 산출됩니다.

참고

몇몇 내장 상수가 전역 변수로 사용할 수 있지만, 여기서 언급된 것들만이 키워드 입니다. 특히, 이 이름들은 재할당되거나 속성(attribute)으로 사용될 수 없습니다.

>>> False = 123
  File "<input>", line 1
   False = 123
   ^^^^^
SyntaxError: cannot assign to False

공식적으로 내장 상수의 문법은 다음과 같습니다.

builtin_constant: 'True' | 'False' | 'None' | '...'

6.2.2. 식별자 (이름)

아톰으로 등장하는 식별자는 이름입니다. 어휘 정의에 대해서는 이름(식별자 및 키워드) 섹션을, 이름과 연결에 대한 문서는 이름과 연결(binding) 섹션을 보세요.

이름이 객체에 연결될 때, 아톰의 값을 구하면 객체가 나옵니다. 이름이 연결되지 않았을 때, 값을 구하려고 하면 NameError 예외가 일어납니다.

6.2.2.1. 비공개 이름 뒤섞기(private name mangling)

클래스 정의 내에서 문자 그대로 나타나는 식별자가 두 개 이상의 밑줄로 시작하고 두 개 이상의 밑줄로 끝나지 않는 경우, 해당 클래스의 비공개 이름(private name) 으로 간주됩니다.

더 보기

그것은 클래스 사양 입니다.

더 정확하게 말하면, 비공개 이름은 코드가 생성되기 전에 더 긴 형태로 변환됩니다. 만약 변환된 이름이 255자를 초과하는 경우, 구현에 따라 결과가 달라지는 잘라내기(truncation)가 발생할 수 있습니다.

변환은 식별자가 사용되는 문법적 문맥과는 무관하게 이루어지며, 다음의 비공개 식별자들만 뒤섞기(mangled) 처리됩니다.

  • 대입되거나 읽히는 변수의 이름으로 사용되는 모든 이름 또는 액세스되는 속성의 이름입니다.

    그러나 중첩된 함수, 클래스 및 타입 별칭의 __name__ 속성은 뒤섞기 처리되지 않습니다.

  • 임포트된 모듈의 이름입니다(예를 들어, import __spam 에서 __spam). 모듈이 패키지의 일부인 경우(즉, 이름에 점이 포함된 경우)에는 해당 이름이 뒤섞기 처리되지 않습니다. 예를 들어, import __foo.bar 에서의 __foo 는 뒤섞기 처리되지 않습니다.

  • 임포트된 멤버의 이름입니다(예를 들어, from spam import __f``에서 ``__f).

변환 규칙은 다음과 같이 정의됩니다.

  • 선행 밑줄을 제거하고 단일 선행 밑줄을 추가한 클래스 이름이 식별자 앞에 삽입됩니다. 예를 들어, Foo, _Foo 또는 __Foo 라는 이름의 클래스에서 나타나는 식별자 __spam_Foo__spam 으로 변환됩니다.

  • 클래스 이름이 밑줄로만 구성된 경우 변환은 유지(identity)됩니다. 예를 들어, _ 또는 __ 라는 이름의 클래스에서 나타나는 식별자 __spam 은 그대로 유지됩니다.

6.2.3. 리터럴 (Literals)

리터럴(literal) 은 값의 텍스트 표현입니다. 파이썬은 수치, 문자열 및 바이트 리터럴을 지원합니다. 포맷 스트링템플릿 스트링 은 문자열 리터럴로 처리됩니다.

수치 리터럴은 정수, 부동 소수점 수 또는 허수 중 하나를 나타내는 단일 NUMBER 토큰으로 구성됩니다. 자세한 내용은 어휘 분석 문서의 숫자 리터럴 섹션을 참조하십시오.

문자열 및 바이트 리터럴은 여러 토큰으로 구성될 수 있습니다. 자세한 내용은 문자열 리터럴 연결 섹션을 참조하십시오.

참고로 -3``이나 ``3+4.2j``와 같은 음수 복소수는 문법적으로 리터럴이 아니라, ``- 또는 + 연산자를 포함하는 단항 또는 이항 산술 연산입니다.

리터럴을 평가하면 해당 값을 가진 특정 타입(int, float, complex, str, bytes 또는 Template)의 객체가 산출됩니다. 부동 소수점 및 허수 리터럴의 경우 값이 근사치로 처리될 수 있습니다.

리터럴에 대한 정식 문법은 다음과 같습니다.

literal: strings | NUMBER

6.2.3.1. 리터럴과 객체 아이덴티티

모든 리터럴은 불변 데이터형에 대응하기 때문에, 객체의 아이덴티티는 값 보다 덜 중요합니다. 같은 값의 리터럴에 대해 반복적으로 값을 구하면 (프로그램 텍스트의 같은 장소에 있거나 다른 장소에 있을 때) 같은 객체를 얻을 수도 있고, 같은 값의 다른 객체를 얻을 수도 있습니다.

CPython 구현 상세

예를 들어, CPython에서 동일한 값을 가진 작은(small) 정수들은 동일한 객체로 평가됩니다:

>>> x = 7
>>> y = 7
>>> x is y
True

그러나 큰 정수들은 서로 다른 객체로 평가됩니다:

>>> x = 123456789
>>> y = 123456789
>>> x is y
False

이 동작은 향후 CPython 버전에서 변경될 수 있습니다. 특히, “작은” 정수와 “큰” 정수의 경계는 이미 과거에 변경된 적이 있습니다.

CPython은 is 를 사용하여 리터럴을 비교할 때 SyntaxWarning 을 발생시킵니다:

>>> x = 7
>>> x is 7
<input>:1: SyntaxWarning: "is" with 'int' literal. Did you mean "=="?
True

자세한 내용은 is 연산자를 사용한 아이덴티티 검사는 언제 신뢰할 수 있습니까? 를 참조하십시오.

Template strings 는 불변이지만 Interpolation 값으로 가변 객체를 참조할 수 있습니다. 이 섹션의 목적상, 두 t-strings가 구조와 값의 identity 가 모두 일치하면 “동일한 값”을 가진 것으로 간주합니다.

현재 템플릿 문자열을 평가할 때마다 서로 다른 객체가 생성됩니다.

6.2.3.2. 문자열 리터럴 연결

서로 다른 따옴표 형식을 사용할 수 있는 여러 개의 인접한 문자열 또는 바이트 리터럴이 허용되며, 그 의미는 이를 연결한 것과 동일합니다:

>>> "hello" 'world'
"helloworld"

이 기능은 구문 수준에서 정의되므로 리터럴에만 적용됩니다. 실행 시간에 문자열 표현식을 연결하려면 ‘+’ 연산자를 사용할 수 있습니다:

>>> greeting = "Hello"
>>> space = " "
>>> name = "Blaise"
>>> print(greeting + space + name)   # not: print(greeting space name)
Hello Blaise

리터럴 연결은 로우 문자열, 삼중 따옴표 문자열, 포맷 문자열 리터럴을 자유롭게 혼합할 수 있습니다. 예를 들어:

>>> "Hello" r', ' f"{name}!"
"Hello, Blaise!"

이 기능은 필요한 백슬래시 수를 줄이고, 긴 문자열을 여러 줄에 걸쳐 편리하게 나누고, 또는 문자열의 일부에 주석을 추가하는 데 사용할 수 있습니다. 예를 들어:

re.compile("[A-Za-z_]"       # 문자 또는 밑줄
           "[A-Za-z0-9_]*"   # 문자, 숫자 또는 밑줄
          )

그러나 바이트 리터럴은 다른 종류의 문자열 리터럴이 아닌 오직 다른 바이트 리터럴과만 결합할 수 있습니다. 또한, 템플릿 문자열 리터럴은 동일한 유형의 템플릿 문자열 리터럴과만 결합할 수 있습니다:

>>> t"Hello" t"{name}!"
Template(strings=('Hello', '!'), interpolations=(...))

형식적으로:

strings: (STRING | fstring)+ | tstring+

6.2.4. 괄호로 묶인 그룹

괄호로 묶인 그룹(parenthesized group) 은 괄호로 둘러싸인 표현식입니다. 이 그룹은 내부의 표현식과 동일한 값을 산출합니다.

그룹은 수학 표기법과 마찬가지로 연산자 우선순위 를 재정의하거나 명확하게 하는 데 사용됩니다. 예를 들어:

>>> 3 << 2 | 4
12
>>> 3 << (2 | 4)   # |(비트 논리합)의 우선순위 재정의
192
>>> (3 << 2) | 4   # 괄호가 없는 경우와 동일함 (하지만 더 명확함)
12

괄호 안에 있는 모든 것이 그룹 은 아니라는 점에 주의하십시오. 구체적으로, 괄호로 묶인 그룹은 반드시 단 하나의 표현식을 포함해야 하며 쉼표로 끝날 수 없습니다. 다른 괄호 형태는 tuple displaysgenerator expressions 를 참조하십시오.

공식적으로 그룹의 문법은 다음과 같습니다.

group: '(' assignment_expression ')'

6.2.5. 컨테이너 디스플레이

내장 컨테이너(리스트, 집합, 튜플 또는 딕셔너리)를 구성하기 위해 Python은 displays 라고 불리는 특별한 문법을 제공합니다. 네 가지 유형의 디스플레이 사이에는 미묘한 차이가 있으며 이는 다음 섹션에서 자세히 다룹니다. 그러나 모든 디스플레이는 쌍을 이루는 구분 기호로 둘러싸인 쉼표로 구분된 항목들로 구성됩니다.

예를 들어, 리스트 디스플레이 는 대괄호로 둘러싸인 일련의 표현식입니다:

>>> ["one", "two", "three"]
['one', 'two', 'three']
>>> [1 + 2, 2 + 3]
[3, 5]

리스트, 튜플, 딕셔너리 디스플레이에서(집합 제외), 해당 시리즈는 비어 있을 수 있습니다:

>>> []  # 빈 리스트
[]
>>> ()  # 빈 튜플
()
>>> {}  # 빈 딕셔너리
{}

시리즈가 비어 있지 않은 경우, 항목 뒤에 추가적인 쉼표를 붙일 수 있으며 이는 아무런 영향을 주지 않습니다:

>>> ["one", "two", "three",]  # "three" 뒤의 쉼표 주의
['one', 'two', 'three']

참고

후행 쉼표는 여러 줄에 걸쳐 나열되는 디스플레이( implicit line joining 사용)에서 자주 쓰이며, 이 경우 향후 프로그래머가 마지막에 새로운 항목을 추가할 때 기존 줄을 수정할 필요가 없습니다:

>>> [
...     'one',
...     'two',
...     'three',
... ]
['one', 'two', 'three']

실행 시 디스플레이가 평가될 때, 나열된 항목들은 왼쪽에서 오른쪽으로 평가되어 적절한 유형의 새로운 컨테이너에 배치됩니다.

튜플, 리스트, 집합 디스플레이(딕셔너리 제외)의 경우, 어떤 항목이라도 별표(*)를 접두사로 가질 수 있습니다. 이는 iterable unpacking 을 나타냅니다. 실행 시 별표가 붙은 표현식은 반드시 반복 가능한 객체(iterable)로 평가되어야 하며, 그 내용이 언 패킹 위치에 컨테이너에 삽입됩니다. 예를 들어:

>>> numbers = (1, 2)
>>> [*numbers, 'word', *numbers]
[1, 2, 'word', 1, 2]

딕셔너리 디스플레이는 별표 두 개(**)로 표기하는 dictionary unpacking 이라는 유사한 메커니즘을 사용합니다. 자세한 내용은 딕셔너리 디스플레이 를 참조하십시오.

A more advanced form of displays are comprehensions, where items are computed via a set of looping and filtering instructions. See the 컴프리헨션 section for details.

Added in version 3.5: 디스플레이에서의 iterable 및 딕셔너리 언 패킹은 원래 PEP 448 에서 제안되었습니다.

6.2.5.1. 리스트 디스플레이

list display 는 대괄호로 둘러싸인, 비어 있을 수 있는 일련의 표현식입니다. 예를 들어:

>>> ["one", "two", "three"]
['one', 'two', 'three']
>>> ["one"]  # 한 요소 리스트
['one']
>>> []       # 빈 리스트
[]

디스플레이에 대한 일반적인 정보는 컨테이너 디스플레이 를 참조하십시오.

리스트 디스플레이의 공식 문법은 다음과 같습니다.

list: '[' [flexible_expression_list] ']'

6.2.5.2. 집합 디스플레이

set display 는 중괄호로 둘러싸인, 비어 있지 않은 일련의 표현식입니다. 예를 들어:

>>> {"one", "two", "three"}
{'one', 'three', 'two'}
>>> {"one"}  # 한 요소 집합
{'one'}

디스플레이에 대한 일반적인 정보는 컨테이너 디스플레이 를 참조하십시오.

빈 집합을 위한 특별한 구문은 없습니다. {} 리터럴은 빈 딕셔너리를 생성하는 dictionary display 입니다. 빈 집합을 얻으려면 인자 없이 set() 를 호출하십시오.

집합 디스플레이의 공식 문법은 다음과 같습니다.

set: '{' flexible_expression_list '}'

6.2.5.3. 튜플 디스플레이

tuple display 은 괄호로 둘러싸인 일련의 표현식입니다. 예를 들어:

>>> (1, 2)
(1, 2)
>>> ()  # 빈 튜플
()

디스플레이에 대한 일반적인 정보는 컨테이너 디스플레이 를 참조하십시오.

모호성을 피하기 위해 튜플 디스플레이가 정확히 하나의 요소를 가지는 경우 후행 쉼표가 필요합니다. 쉼표가 없으면 parenthesized group 가 됩니다:

>>> ('single',)  # 단일 요소 튜플
('single',)
>>> ('single')   # 쉼표 없음: 단일 문자열
'single'

다시 말해, 튜플 디스플레이는 다음 중 하나를 포함하는 괄호로 묶인 리스트입니다.

  • 쉼표로 구분된 두 개 이상의 표현식 또는

  • 각각 뒤에 쉼표가 붙은 영 개 이상의 표현식.

튜플은 불변이므로 object identity rules for literals 가 튜플에도 적용됩니다. 즉, 실행 시 같은 값을 가진 두 개의 튜플 인스턴스가 동일한 객체를 반환할 수도 있고 그렇지 않을 수도 있습니다.

참고

파이썬 문법에는 expression lists 도 포함되는데, 이는 쉼표로 구분된 표현식 목록이 괄호로 둘러싸여 있지 않지만 튜플로 평가되는 경우를 말합니다.

다시 말해, 튜플 문법에 있어서는 괄호의 사용보다 쉼표가 더 중요합니다. 빈 튜플만이 쉼표 없이 기술됩니다.

튜플 디스플레이의 공식 문법은 다음과 같습니다.

tuple:
   | '(' flexible_expression (',' flexible_expression)+ [','] ')'
   | '(' flexible_expression ',' ')'
   | '(' ')'

6.2.5.4. 딕셔너리 디스플레이

dictionary display 는 중괄호로 둘러싸인, 비어 있을 수 있는 일련의 dict items 입니다. 각 딕셔너리 아이템은 콜론으로 구분된 두 표현식의 쌍, 즉 key 와 그에 대응하는 value 입니다. 예를 들어:

>>> {1: 'one', 2: 'two'}
{1: 'one', 2: 'two'}

실행 시 딕셔너리 컴프리헨션이 평가될 때, 표현식은 왼쪽에서 오른쪽으로 평가됩니다. 각 키 객체는 해당 값을 저장하기 위한 딕셔너리의 키로 사용됩니다. 이는 컴프리헨션 내에 동일한 키를 여러 번 지정할 수 있음을 의미하며, 이 경우 최종 딕셔너리에서 해당 키의 값은 마지막에 주어진 값이 됩니다. 예를 들어:

>>> {
...     1: 'this will be overridden',
...     2: 'two',
...     1: 'also overridden',
...     1: 'one',
... }
{1: 'one', 2: 'two'}

키-값 쌍 대신 딕셔너리 아이템은 별표 두 개 ** 가 접두사로 붙은 표현식일 수 있습니다. 이는 dictionary unpacking 을 의미합니다. 실행 시 이 표현식은 반드시 mapping 으로 평가되어야 하며, 매핑의 각 항목이 새 딕셔너리에 추가됩니다. 키-값 쌍과 마찬가지로, 나중에 나오는 값은 앞선 아이템이나 언 패킹에 의해 설정된 값을 대체합니다. 이는 기본값 집합을 재정의하는 데 사용될 수 있습니다:

>>> defaults = {'color': 'blue', 'count': 8}
>>> overrides = {'color': 'yellow'}
>>> {**defaults, **overrides}
{'color': 'yellow', 'count': 8}

Added in version 3.5: PEP 448 에서 처음 제안된 딕셔너리 디스플레이로의 언 패킹.

딕셔너리 디스플레이의 공식 문법은 다음과 같습니다.

dict:                   '{' [double_starred_kvpairs] '}'
double_starred_kvpairs: ','.double_starred_kvpair+ [',']
double_starred_kvpair:  '**' or_expr | kvpair
kvpair:                 expression ':' expression

6.2.6. 컴프리헨션

리스트, 집합, 딕셔너리 컴프리헨션(comprehensions) 은 항목이 명시적으로 나열되는 대신 일련의 반복 및 필터링 명령을 통해 계산되는 방식의 컨테이너 디스플레이 형태입니다.

가장 단순한 형태의 컴프리헨션은 단일 표현식과 그 뒤를 따르는 for 절로 구성됩니다. for 절은 끝에 콜론이 붙지 않은 for 문 의 헤더와 동일한 구문을 가집니다.

예를 들어, 처음 10개 제곱수의 리스트는 다음과 같습니다:

>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

At run time, a list comprehension creates a new list. The expression after in must evaluate to an iterable. For each element of this iterable, the element is bound to the for clause’s target as in a for statement, then the expression before for is evaluated with the target in scope and the result is added to the new list. Thus, the example above is roughly equivalent to defining and calling the following function:

def make_list_of_squares(iterable):
    result = []
    for x in iterable:
        result.append(x**2)
    return result

make_list_of_squares(range(10))

집합 컴프리헨션도 유사하게 작동합니다. 예를 들어, 다음과 같은 소문자 집합이 있습니다:

>>> {x.lower() for x in ['a', 'A', 'b', 'C']}
{'c', 'a', 'b'}

실행 시 이는 다음 함수를 호출하는 것과 거의 동일합니다:

def make_lowercase_set(iterable):
    result = set(iterable)
    for x in iterable:
        result.append(x.lower())
    return result

make_lowercase_set(['a', 'A', 'b', 'C'])

딕셔너리 컴프리헨션은 표현식 대신 콜론으로 구분된 키-값 쌍으로 시작합니다. 예를 들어:

>>> {func.__name__: func for func in [print, hex, any]}
{'print': <built-in function print>,
 'hex': <built-in function hex>,
 'any': <built-in function any>}

실행 시 이는 다음과 거의 동일합니다:

def make_dict_mapping_names_to_functions(iterable):
    result = {}
    for func in iterable:
        result[func.__name__] = func
    return result

iterable([print, hex, any])

다른 종류의 딕셔너리 디스플레이와 마찬가지로, 동일한 키를 여러 번 지정할 수 있습니다. 앞선 값은 나중에 평가되는 값으로 덮어써집니다.

튜플 컴프리헨션 은 없습니다. 대신 유사한 구문이 제너레이터 표현식 에 사용되며, 이를 통해 다음과 같이 튜플을 생성할 수 있습니다:

>>> tuple(x**2 for x in range(10))
(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)

버전 3.8에서 변경: 파이썬 3.8 이전에는, 딕셔너리 컴프리헨션에서, 키와 값의 평가 순서가 잘 정의되어 있지 않았습니다. CPython에서, 값이 키보다 먼저 평가되었습니다. 3.8부터는, PEP 572의 제안에 따라 키가 값보다 먼저 평가됩니다.

6.2.6.1. 컴프리헨션 내에서의 필터링

for 절 뒤에 표현식이 포함된 if 절이 올 수 있습니다.

예를 들어, math 모듈의 이름 중 f 로 시작하는 것들의 리스트는 다음과 같습니다:

>>> [name for name in vars(math) if name.startswith('f')]
['fabs', 'factorial', 'floor', 'fma', 'fmod', 'frexp', 'fsum']

실행 시 if 뒤의 표현식은 각 요소가 결과 컨테이너에 추가되기 전에 평가되며, 결과가 거짓(False)이면 해당 요소는 건너뜁니다. 따라서 위의 예제는 다음과 같은 함수를 정의하고 호출하는 것과 거의 대응됩니다:

def get_math_f_names(iterable):
    result = []
    for name in iterable:
        if name.startswith('f'):
           result.append(name)
    return result

get_math_f_names(vars(math))

필터링은 더 복잡한 컴프리헨션의 특수한 경우입니다. 자세한 설명은 다음 섹션을 참조하십시오.

6.2.6.2. 복잡한 컴프리헨션

일반적으로 컴프리헨션의 첫 번째 for 절 뒤에 0개 이상의 추가적인 for 또는 if 절이 올 수 있습니다. 예를 들어, 두 개의 파이썬 모듈에 노출된 이름들 중 a 로 시작하는 것만 포함되도록 필터링된 리스트는 다음과 같습니다:

>>> import array
>>> import math
>>> [
...     name
...     for module in [array, math]
...     for name in vars(module)
...     if name.startswith('a')
... ]
['array', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh']

실행 시 이는 다음을 정의하고 호출하는 것과 거의 대응됩니다:

def get_a_names(iterable):
    result = []
    for module in iterable:
        for name in vars(module):
            if name.startswith('a'):
                result.append(name)
    return result

get_a_names([array, math])

새 컨테이너의 요소들은 각 for 또는 if 절을 하나의 블록으로 간주하고 왼쪽에서 오른쪽으로 중첩하며, 가장 안쪽 블록에 도달할 때마다 표현식을 평가하여 생성되는 결과(또는 딕셔너리 항목)들입니다.

가장 왼쪽 for 절에 있는 이터러블 표현식을 제외하고, 컴프리헨션은 별도로 묵시적으로 중첩된 스코프에서 실행됩니다. 이는 대상 리스트에서 할당되는 이름이 외부 스코프로 “유출”되지 않도록 보장합니다. 예를 들면:

>>> x = 'old value'
>>> [x**2 for x in range(10)]  # 이 `x`는 컴프리헨션 내부에서만 유효함
>>> x
'old value'

가장 왼쪽 for 절의 이터러블 표현식은 외부 스코프에서 직접 평가된 후 묵시적으로 중첩된 스코프로 인자가 전달됩니다.

뒤따르는 for 절과 가장 왼쪽 for 절의 모든 필터 조건은 가장 왼쪽 이터러블에서 얻은 값에 의존할 수 있으므로 외부 스코프에서 평가될 수 없습니다.

컴프리헨션이 항상 적절한 형의 컨테이너가 되게 하려고, 묵시적으로 중첩된 스코프에서 yieldyield from 표현식은 금지됩니다.

할당 표현식 <assignment-expressions>`은 컴프리헨션의 이터러블 표현식(즉, :keyword:!in` 키워드 뒤의 표현식) 내부나 클래스 정의에 직접 나타나는 컴프리헨션 내 어디에서도 허용되지 않습니다.

버전 3.8에서 변경: yieldyield from 은 묵시적으로 중첩된 스코프에서 금지됩니다.

6.2.6.3. 컴프리헨션에서의 언패킹(Unpacking)

리스트 또는 집합 컴프리헨션의 표현식이 별표(*)로 표시된 경우, 결과는 0개 이상의 요소를 생성하기 위해 언패킹(unpacked) 됩니다.

이것은 종종 리스트를 “평탄화(flattening)”하는 데 사용되며, 예를 들면:

>>> students = ['Petr', 'Blaise', 'Jarka']
>>> teachers = ['Salim', 'Bartosz']
>>> lists_of_people = [students, teachers]
>>> [*people for people in lists_of_people]
['Petr', 'Blaise', 'Jarka', 'Salim', 'Bartosz']

실행 시 이 컴프리헨션은 다음과 거의 대응됩니다:

def flatten_names(lists_of_people):
    result = []
    for people in lists_of_people:
        result.extend(people)
    return result

딕셔너리 컴프리헨션에서 이중 별표(**) 표현식은 평가된 후 딕셔너리 언패킹 을 사용하여 펼쳐지며, 새로운 딕셔너리에 0개 이상의 키/값 쌍이 삽입됩니다. 다른 종류의 딕셔너리 디스플레이와 마찬가지로, 동일한 키가 여러 번 지정되면 결과 딕셔너리의 해당 값은 마지막에 지정된 것으로 결정됩니다.

예를 들어:

>>> system_defaults = {'color': 'blue', 'count': 8}
>>> user_defaults = {'color': 'yellow'}
>>> overrides = {'count': 5}

>>> configuration_sets = [system_defaults, user_defaults, overrides]

>>> {**d for d in configuration_sets}
{'color': 'yellow', 'count': 5}

Added in version 3.15: *** 연산자를 사용하여 컴프리헨션에서 언패킹하는 기능은 PEP 798 에서 도입되었습니다.

6.2.6.4. 비동기 컴프리헨션

In an async def function, an async for clause may be used to iterate over a asynchronous iterator. A comprehension in an async def function may consist of either a for or async for clause following the leading expression, may contain additional for or async for clauses, and may also use await expressions.

컴프리헨션이 async for 절을 포함하거나, 가장 왼쪽 for 절의 이터러블 표현식을 제외한 곳에 await 표현식이나 다른 비동기 컴프리헨션을 포함하는 경우 이를 비동기 컴프리헨션(asynchronous comprehension) 이라고 합니다. 비동기 컴프리헨션은 나타나는 코루틴 함수의 실행을 중단할 수 있습니다.

Added in version 3.6: 비동기 컴프리헨션은 PEP 530 에서 도입되었습니다.

버전 3.11에서 변경: 이제 비동기 함수 내의 컴프리헨션 안에서도 비동기 컴프리헨션을 사용할 수 있습니다. 외부 컴프리헨션은 묵시적으로 비동기가 됩니다.

6.2.6.5. 컴프리헨션에 대한 공식 문법

컴프리헨션의 공식 문법은 다음과 같습니다:

listcomp:      '[' comprehension ']'
setcomp:       '{' comprehension '}'
comprehension: flexible_expression for_if_clause+

dictcomp:
    | '{' kvpair for_if_clause+ '}'
    | '{' '**' expression for_if_clause+ '}'

for_if_clause:
    | ['async'] 'for' target_list 'in' or_test ('if' or_test)*

6.2.7. 제너레이터 표현식 (Generator expressions)

제너레이터 표현식(generator expressions) 의 구문은 리스트 컴프리헨션 과 동일하지만, 대괄호 대신 괄호로 감싸져 있습니다. 예를 들면:

>>> iterator = (x ** 2 for x in range(10))
>>> iterator
<generator object <genexpr> at ...>

At runtime, a generator expression evaluates to a generator iterator which yields the same values as the corresponding list comprehension:

>>> list(iterator)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

따라서 위 예제는 다음과 같은 제너레이터 함수를 정의하고 호출하는 것과 거의 동일합니다:

def make_generator_of_squares(iterator):
    for x in iterator:
        yield x ** 2

make_generator_of_squares(iter(range(10)))

제너레이터 표현식이 유일한 위치 인자이고 키워드 인자가 없는 경우 호출 시 괄호를 생략할 수 있습니다. 자세한 내용은 호출(Calls) 섹션 을 참조하십시오. 예를 들면:

# `sum` 뒤의 두 괄호는 호출 문법의 일부입니다:
>>> sum(x ** 2 for x in range(10))
285

# 생성기가 유일한 인자가 아닌 경우 자체 괄호가 필요합니다:
>>> sum((x ** 2 for x in range(10)), start=1000)
1285

가장 왼쪽 for 절의 이터러블 표현식은 즉시 평가되므로, 이 표현식에 의해 발생하는 오류는 첫 번째 값을 가져오는 시점이 아니라 제너레이터 표현식이 정의된 지점에서 발생합니다:

>>> (x ** 2 for x in nonexistent_iterable)
Traceback (most recent call last):
  ...
NameError: name 'nonexistent_iterable' is not defined

표현식이 평가된 후, 마치 iter() 가 호출된 것처럼 결과로부터 이터레이터가 생성됩니다. 이터레이터를 생성할 때 발생하는 모든 오류도 즉시 발생합니다:

>>> (x ** 2 for x in None)
Traceback (most recent call last):
  ...
TypeError: 'NoneType' object is not iterable

그 외의 모든 표현식은 일반적인 제너레이터와 동일한 방식으로 게으르게(lazily) 평가됩니다(즉, 이터레이터가 값을 내보내도록 요청될 때):

>>> iterator = (nonexistent_value for x in range(10))
>>> iterator
<generator object <genexpr> at ...>
>>> list(iterator)
Traceback (most recent call last):
  ...
NameError: name 'nonexistent_value' is not defined
>>> iterator = (x * y for x in range(10) for y in nonexistent_iterable)
>>> iterator
<generator object <genexpr> at ...>
>>> list(iterator)
Traceback (most recent call last):
  ...
NameError: name 'nonexistent_iterable' is not defined

제너레이터 표현식 자체의 예상되는 동작을 방해하지 않기 위해, 묵시적으로 중첩된 스코프 내에서 yieldyield from 표현식은 금지됩니다.

생성기 표현식이 async for 절이나 await 표현식을 포함하면 비동기 생성기 표현식 (asynchronous generator expression) 이라고 불립니다. 비동기 생성기 표현식은 새로운 비동기 생성기 객체를 반환하며, 이는 비동기 이터레이터입니다 (비동기 이터레이터(Asynchronous Iterators) 를 참조하세요).

제너레이터 표현식의 공식 문법은 다음과 같습니다.

generator_expression: "(" comprehension ")"

Added in version 3.6: 비동기식 제너레이터 표현식이 도입되었습니다.

버전 3.7에서 변경: 파이썬 3.7 이전에는, 비동기 제너레이터 표현식이 async def 코루틴에만 나타날 수 있었습니다. 3.7부터는, 모든 함수가 비동기식 제너레이터 표현식을 사용할 수 있습니다.

버전 3.8에서 변경: yieldyield from 은 묵시적으로 중첩된 스코프에서 금지됩니다.

6.2.8. 일드 표현식(Yield expressions)

yield_atom:       "(" yield_expression ")"
yield_from:       "yield" "from" expression
yield_expression: "yield" yield_list | yield_from

The yield expression is used when defining a generator function or an asynchronous generator function and thus can only be used in the body of a function definition. Using a yield expression in a function’s body causes that function to be a generator function, and using it in an async def function’s body causes that coroutine function to be an asynchronous generator function. For example:

def gen():  # 제너레이터 함수 정의
    yield 123

async def agen(): # 비동기 제너레이터 함수 정의
    yield 123

둘러싸는 스코프에 대한 부작용으로 인해, yield 표현식은 컴프리헨션과 제너레이터 표현식을 구현하는 데 사용되는 묵시적으로 정의된 스코프에 사용될 수 없습니다.

버전 3.8에서 변경: 일드 표현식은 컴프리헨션과 제너레이터 표현식을 구현하는 데 사용되는 묵시적으로 정의된 스코프에서 금지됩니다.

제너레이터 함수는 다음에서 설명합니다. 반면에 비동기 제너레이터 함수는 비동기 제너레이터 함수 섹션에서 별도로 설명합니다.

제너레이터 함수가 호출되면 제너레이터라고 알려진 이터레이터를 반환합니다. 그 제너레이터는 제너레이터 함수의 실행을 제어합니다. 실행은 제너레이터의 메서드 중 하나가 호출될 때 시작됩니다. 그때가 되면 실행은 첫 번째 yield 표현식으로 진행되며, 여기서 다시 일시 중지되고 yield_list 의 값을 제너레이터 호출자에게 반환하거나, 만약 yield_list 가 생략되었다면 None 을 반환합니다. ‘일시 중단된다(suspended)’란 모든 지역 상태가 유지됨을 의미하며, 여기에는 지역 변수의 현재 바인딩, 명령어 포인터, 내부 평가 스택 및 모든 예외 처리의 상태가 포함됩니다. 제너레이터의 메서드 중 하나를 호출하여 실행이 재개되면, 함수는 마치 yield 표현식이 단지 또 다른 외부 호출인 것처럼 진행될 수 있습니다. 재개 후 yield 표현식의 값은 실행을 재개한 방법에 따라 달라집니다. 만약 __next__() 가 사용되었다면 (일반적으로 fornext() 내장 함수를 통해), 그 결과는 None 입니다. 그렇지 않고, send() 가 사용되면, 그 결과는 해당 메서드에 전달된 값이 됩니다.

이 모든 것들은 제너레이터 함수를 코루틴과 아주 비슷하게 만듭니다; 여러 번 결과를 만들고, 하나 이상의 진입 지점을 갖고 있으며, 실행이 일시 중지될 수 있습니다. 유일한 차이점은 제너레이터 함수는 yield 한 후에 실행이 어디에서 계속되어야 하는지를 제어할 수 없다는 점입니다; 제어는 항상 제너레이터의 호출자로 전달됩니다.

일드 표현식은 try 구조물의 어디에서건 허락됩니다. 제너레이터가 (참조 횟수가 0이 되거나 가비지 수거됨으로써) 파이널라이즈(finalize)되기 전에 재개되지 않으면, 제너레이터-이터레이터의 close() 메서드가 호출되어, 대기 중인 finally 절이 실행되도록 허락합니다.

yield from <expr> 이 사용될 때, 제공된 표현식은 어터러블이어야 합니다. 그 이터러블을 이터레이트 해서 생성되는 값들은 현재 제너레이터 메서드의 호출자에게 바로 전달됩니다. send() 로 전달된 모든 값과 throw() 로 전달된 모든 예외는 밑에 있는(underlying) 이터레이터가 해당 메서드를 갖고 있다면 그곳으로 전달됩니다. 그렇지 않다면, send()AttributeErrorTypeError 를 일으키지만, throw() 는 전달된 예외를 즉시 일으킨다.

밑에 있는 이러레이터가 완료될 때, 발생하는 StopIteration 인스턴스의 value 어트리뷰트는 일드 표현식의 값이 됩니다. StopIteration 를 일으킬 때 명시적으로 설정되거나, 서브 이터레이터가 제너레이터일 경우는 자동으로 이루어집니다 (서브 제너레이터가 값을 돌려(return)줌으로써).

버전 3.3에서 변경: 서브 이터레이터로 제어 흐름을 위임하는 yield from <expr> 를 추가했습니다.

일드 표현식이 대입문의 우변에 홀로 나온다면 괄호를 생략할 수 있습니다.

더 보기

PEP 255 - 간단한 제너레이터

파이썬에 제너레이터와 yield 문을 추가하는 제안.

PEP 342 - 개선된 제너레이터를 통한 코루틴

제너레이터의 API와 문법을 개선해서, 간단한 코루틴으로 사용할 수 있도록 만드는 제안.

PEP 380 - 서브 제너레이터로 위임하는 문법

서브 제너레이터로의 위임(delegation)을 용이하게 하는 yield_from 구문을 도입하자는 제안입니다.

PEP 525 - 비동기 제너레이터

코루틴 함수에 제너레이터 기능을 추가하여 PEP 492을 확장한 제안.

6.2.8.1. 제너레이터-이터레이터 메서드

이 서브섹션은 제너레이터 이터레이터의 메서드들을 설명합니다. 제너레이터 함수의 실행을 제어하는데 사용될 수 있습니다.

제너레이터가 이미 실행 중일 때 아래에 나오는 메서드들을 호출하면 ValueError 예외를 일으키는 것에 주의해야 합니다.

generator.__next__()

제너레이터 함수의 실행을 시작하거나 마지막으로 실행된 yield 표현식에서 이를 재개합니다. 제너레이터 함수가 __next__() 메서드로 재개될 때, 현재의 yield 표현식은 항상 None 으로 평가됩니다. 그런 다음 실행은 다음 yield 표현식으로 이어지며, 여기서 제너레이터는 다시 중단되고 yield_list 값이 __next__() 호출자에게 반환됩니다. 제너레이터가 다른 값을 출력하지 않고 종료되면 StopIteration 예외가 발생합니다.

이 메서드는 보통 묵시적으로 호출됩니다, 예를 들어, for 루프나 내장 next() 함수에 의해.

generator.send(value)

실행을 재개하고 제너레이터 함수로 값을 “보냅니다(send)”. value 인자는 현재 일드 표현식의 값이 됩니다. send() 메서드는 제너레이터가 yield 하는 다음 값을 돌려주거나, 제너레이터가 다른 값을 yield 하지 않고 종료하면 StopIteration 을 일으킵니다. send() 가 제너레이터를 시작시키도록 호출될 때, 값을 받을 일드 표현식이 없으므로, 인자로는 반드시 None 을 전달해야 합니다.

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

제너레이터가 중단된 지점에서 예외를 발생시키고 제너레이터 함수에 의해 다음으로 반환되는 값을 반환합니다. 제너레이터가 다른 값을 반환하지 않고 종료되면 StopIteration 예외가 발생합니다. 제너레이터 함수가 전달된 예외를 처리하지 않거나 다른 예외를 발생시키는 경우, 해당 예외는 호출자에게 전파됩니다.

일반적인 사용 시, 이 메서드는 raise 키워드가 사용되는 방식과 유사하게 단일 예외 인스턴스와 함께 호출됩니다.

그러나 이전 버전과의 호환성을 위해 오래된 파이썬 버전의 관례를 따르는 두 번째 시그니처도 지원됩니다. type 인자는 예외 클래스여야 하며, value 는 예외 인스턴스여야 합니다. value 가 제공되지 않으면 type 생성자가 호출되어 인스턴스를 가져옵니다. traceback 이 제공되면 예외에 설정되며, 그렇지 않으면 value 에 저장된 기존의 __traceback__ 속성이 삭제될 수 있습니다.

버전 3.12에서 변경: 두 번째 시그니처인 (type[, value[, traceback]])는 더 이상 권장되지 않으며 향후 파이썬 버전에서 제거될 수 있습니다.

generator.close()

제너레이터 함수가 중단된 지점에서 GeneratorExit 예외를 발생시킵니다(throw(GeneratorExit) 호출과 동일). 예외는 제너레이터가 중단되었던 yield 표현식에 의해 발생합니다. 만약 제너레이터 함수가 이 예외를 처리하고 값을 반환하면, 이 값이 close() 에서 반환됩니다. 제너레이터 함수가 이미 닫혔거나, 예외를 처리하지 않아 GeneratorExit 를 발생시키는 경우, close()None 을 반환합니다. 만약 제너레이터가 값을 yield 하는 경우, RuntimeError 가 발생합니다. 제너레이터가 다른 예외를 발생시키면 호출자에게 전파됩니다. 제너레이터가 예외나 일반 종료로 이미 종료된 상태라면, close()None 을 반환하며 아무런 영향도 주지 않습니다.

버전 3.13에서 변경: 제너레이터가 종료될 때 값을 반환하는 경우, 해당 값이 close() 에 의해 반환됩니다.

6.2.8.2. 사용 예

여기에 제너레이터와 제너레이터 함수의 동작을 시연하는 간단한 예가 있습니다:

>>> def echo(value=None):
...     print("Execution starts when 'next()' is called for the first time.")
...     try:
...         while True:
...             try:
...                 value = (yield value)
...             except Exception as e:
...                 value = e
...     finally:
...         print("Don't forget to clean up when 'close()' is called.")
...
>>> generator = echo(1)
>>> print(next(generator))
Execution starts when 'next()' is called for the first time.
1
>>> print(next(generator))
None
>>> print(generator.send(2))
2
>>> generator.throw(TypeError, "spam")
TypeError('spam',)
>>> generator.close()
Don't forget to clean up when 'close()' is called.

yield from 을 사용하는 예는, “What’s New in Python.” 에 있는 PEP 380: 서브 제너레이터로 위임하는 문법 을 보세요.

6.2.8.3. 비동기 제너레이터 함수

async def 를 사용한 함수나 메서드에서 일드 표현식의 존재는 그 함수를 비동기 제너레이터 함수로 정의합니다.

비동기 제너레이터 함수가 호출되면, 비동기 제너레이터 객체로 알려진 비동기 이터레이터를 돌려줍니다. 그런 다음 그 객체는 제너레이터 함수의 실행을 제어합니다. 비동기 제너레이터 객체는 보통 코루틴 함수의 async for 문에서 사용되는데, 제너레이터 객체가 for 문에서 사용되는 방식과 유사합니다.

비동기 제너레이터의 메서드 중 하나를 호출하면 awaitable 객체가 반환되며, 이 객체가 await될 때 실행이 시작됩니다. 그 시점에 실행은 첫 번째 yield 표현식으로 진행되며, 여기서 다시 일시 중단되어 yield_list 의 값을 기다리는 코루틴에 반환합니다. 제너레이터와 마찬가지로, ‘일시 중단’은 로컬 변수의 현재 바인딩, 명령 포인터, 내부 평가 스택 및 모든 예외 처리 상태를 포함한 모든 로컬 상태가 유지됨을 의미합니다. 비동기 제너레이터의 메서드에 의해 반환된 다음 객체를 await하여 실행이 재개될 때, 함수는 yield 표현식이 단지 또 다른 외부 호출이었던 것처럼 정확하게 진행됩니다. 재성 후 yield 표현식의 값은 실행을 재개한 메서드에 따라 달라집니다. __anext__() 가 사용되는 경우 결과는 None 입니다. 그 외에 asend() 가 사용되는 경우, 결과는 해당 메서드에 전달된 값이 됩니다.

비동기 제너레이터가 break, 호출자 태스크의 취소 또는 기타 예외로 인해 조기에 종료되는 경우, 제너레이터의 비동기 정리(cleanup) 코드가 실행되어 예상치 못한 상황에서 예외를 발생시키거나 컨텍스트 변수에 접근할 수 있습니다. 이는 해당 제너레이터가 의존하는 태스크의 생명 주기가 끝난 후나 이벤트 루프 종료 중 비동기 제너레이터 가비지 컬렉션 훅이 호출되는 시점 등에서 발생할 수 있습니다. 이를 방지하기 위해, 호출자는 반드시 aclose() 메서드를 호출하여 제너레이터를 최종 확정(finalize)하고 이벤트 루프로부터 분리해야 합니다.

비동기 제너레이터 함수에서, 일드 표현식은 try 구조물의 어디에서건 허락됩니다. 하지만, 비동기 제너레이터가 (참조 횟수가 0이 되거나 가비지 수거됨으로써) 파이널라이즈(finalize)되기 전에 재개되지 않으면, try 구조물 내의 일드 표현식은 대기 중인 finally 절을 실행하는 데 실패할 수 있습니다. 이 경우에, 비동기 제너레이터-이터레이터의 aclose() 를 호출하고, 그 결과로 오는 코루틴 객체를 실행해서, 대기 중인 finally 절이 실행되도록 하는 책임은, 비동기 제너레이터를 실행하는 이벤트 루프(event loop)나 스케줄러(scheduler)에게 있습니다.

이벤트 루프 종료 시의 처리를 위해, 이벤트 루프는 비동기 제너레이터-이터레이터를 인자로 받아 아마도 aclose() 를 호출하고 코루틴을 실행하는 finalizer 함수를 정의해야 합니다. 이 finalizersys.set_asyncgen_hooks() 를 호출하여 등록할 수 있습니다. 비동기 제너레이터-이터레이터가 처음으로 반복될 때, 이는 최종 확정 시 호출될 등록된 finalizer 를 저장합니다. finalizer 메서드의 참고 예제는 Lib/asyncio/base_events.py 에 있는 asyncio.Loop.shutdown_asyncgens 구현을 참조하십시오.

표현식 yield from <expr> 를 비동기 제너레이터 함수에서 사용하는 것은 문법 에러다.

6.2.8.4. 비동기 제너레이터-이터레이터 메서드

이 서브섹션은 비동기 제너레이터 이터레이터의 메서드를 설명하는데, 제너레이터 함수의 실행을 제어하는 데 사용됩니다.

async agen.__anext__()

실행 시 비동기 제너레이터를 시작하거나 마지막으로 실행된 yield 표현식에서 재개하는 어웨이터블을 반환합니다. 비동기 제너레이터 함수가 __anext__() 메서드로 재개될 때, 결과로 반환된 어웨이터블 내에서 현재의 yield 표현식은 항상 None 으로 평가되며, 실행 시 다음 yield 표현식으로 진행됩니다. yield 표현식의 yield_list 값은 종료되는 코루틴에 의해 발생한 StopIteration 예외의 값입니다. 비동기 제너레이터가 다른 값을 출력하지 않고 종료되면, 어웨이터블은 대신 비동기 반복이 완료되었음을 알리는 StopAsyncIteration 예외를 발생시킵니다.

이 메서드는 보통 async for 루프에 의해 묵시적으로 호출됩니다.

async agen.asend(value)

실행 시 비동기 제너레이터의 실행을 재개하는 어웨이터블을 반환합니다. 제너레이터의 send() 메서드와 마찬가지로, 이는 비동기 제너레이터 함수에 값을 “보내고(send)”이며, value 인자는 현재 yield 표현식의 결과가 됩니다. asend() 메서드가 반환하는 어웨이터블은 제너레이터에 의해 생성된 다음 값을 발생한 StopIteration 예외의 값으로 반환하거나, 비동기 제너레이터가 다른 값을 출력하지 않고 종료될 경우 StopAsyncIteration 을 발생시킵니다. 비동기 제너레이터 시작을 위해 asend() 를 호출할 때는 이를 받을 수 있는 yield 표현식이 없으므로 인자로 반드시 None 을 전달해야 합니다.

async agen.athrow(value)
async agen.athrow(type[, value[, traceback]])

어웨이터블을 돌려주는데, 비동기 제너레이터가 일시 중지한 지점에 type 형의 예외를 일으키고, 제너레이터 함수가 yield 한 다음 값을 발생하는 StopIteration 예외의 값으로 돌려줍니다. 비동기 제너레이터가 다른 값을 yield 하지 않고 종료하면, 어웨이터블에 의해 StopAsyncIteration 예외가 일어납니다. 제너레이터 함수가 전달된 예외를 잡지 않거나, 다른 예외를 일으키면, 어웨이터블을 실행할 때 그 예외가 어웨이터블의 호출자에게 퍼집니다.

버전 3.12에서 변경: 두 번째 시그니처인 (type[, value[, traceback]])는 더 이상 권장되지 않으며 향후 파이썬 버전에서 제거될 수 있습니다.

async agen.aclose()

어웨이터블을 돌려주는데, 실행하면, 비동기 제너레이터 함수가 일시 정지한 지점으로 GeneratorExit 를 던집니다. 만약 그 이후에 비동기 제너레이터 함수가 우아하게 (gracefully) 종료하거나, 이미 닫혔거나, (그 예외를 잡지 않음으로써) GeneratorExit 를 일으키면, 돌려준 어웨이터블은 StopIteration 예외를 일으킵니다. 이어지는 비동기 제너레이터 호출이 돌려주는 추가의 어웨이터블들은 StopAsyncIteration 예외를 일으킵니다. 만약 비동기 제너레이터가 값을 yield 하면 어웨이터블에 의해 RuntimeError 가 발생합니다. 만약 비동기 제너레이터가 그 밖의 다른 예외를 일으키면, 어웨이터블의 호출자로 퍼집니다. 만약 비동기 제너레이터가 예외나 정상 종료로 이미 종료했으면, 더 이어지는 aclose() 호출은 아무것도 하지 않는 어웨이터블을 돌려줍니다.

6.3. 프라이머리

프라이머리는 언어에서 가장 강하게 결합하는 연산들을 나타냅니다. 문법은 이렇습니다:

primary: atom | attributeref | subscription | call

6.3.1. 어트리뷰트 참조

어트리뷰트 참조는 마침표(period)와 이름이 뒤에 붙은 프라이머리다:

attributeref: primary "." identifier

프라이머리는 어트리뷰트 참조를 지원하는 타입의 객체로 평가되어야 하며, 대부분의 객체가 이를 지원합니다. 그런 다음 이 객체는 식별자와 이름이 일치하는 어트리뷰트를 생성하도록 요청받습니다. 생성되는 유형과 값은 해당 객체에 의해 결정됩니다. 동일한 어트리뷰트 참조를 여러 번 평가하면 서로 다른 객체가 나올 수 있습니다.

이 규칙은 __getattribute__() 메서드 또는 __getattr__() 메서드를 오버라이드하여 사용자 정의할 수 있습니다. __getattribute__() 메서드가 먼저 호출되며, 어트리뷰트가 존재하지 않으면 값을 반환하거나 AttributeError 를 발생시킵니다.

어트리뷰트가 존재하지 않아 AttributeError`가 발생하고 객체에 :meth:!__getattr__` 메서드가 있는 경우, 대체 수단으로 해당 메서드가 호출됩니다.

6.3.2. 서브스크립션 및 슬라이싱

서브스크립션 (subscription) 구문은 보통 컨테이너 에서 요소를 선택하는 데 사용됩니다. 예를 들어, dict 에서 값을 가져올 때 사용됩니다:

>>> digits_by_name = {'one': 1, 'two': 2}
>>> digits_by_name['two']  # 키 'two'를 사용하여 딕셔너리 서브스크립션
2

서브스크립션 구문에서 서브스크립션되는 객체(즉, 프라이머리) 뒤에는 대괄호 안에 있는 서브스크립트 가 옵니다. 가장 단순한 경우, 서브스크립트는 단일 표현식입니다.

서브스크립트의 타입에 따라 다음과 같이 호출됩니다: 매핑의 경우 , 시퀀스의 경우 인덱스, 또는 타입 인자 (제네릭 타입)입니다. 구문적으로 이들은 모두 동일합니다:

>>> colors = ['red', 'blue', 'green', 'black']
>>> colors[3]  # 인덱스 3을 사용하여 리스트 서브스크립션
'black'

>>> list[str]  # 타입 인자 str을 사용하여 리스트 타입 파라미터화
list[str]

At runtime, the interpreter will evaluate the primary and the subscript, and call the primary’s __getitem__() or __class_getitem__() special method with the subscript as argument. For more details on which of these methods is called, see __class_getitem__ 와 __getitem__ 의 비교.

서브스크립션이 작동하는 방식을 보여주기 위해, __getitem__() 을 구현하고 서브스크립트의 값을 출력하는 사용자 정의 객체를 정의할 수 있습니다:

>>> class SubscriptionDemo:
...     def __getitem__(self, key):
...         print(f'subscripted with: {key!r}')
...
>>> demo = SubscriptionDemo()
>>> demo[1]
subscripted with: 1
>>> demo['a' * 3]
subscripted with: 'aaa'

내장 타입이 서브스크립션을 처리하는 방식은 __getitem__() 문서를 참조하십시오.

Subscriptions may also be used as targets in assignment or deletion statements. In these cases, the interpreter will call the subscripted object’s __setitem__() or __delitem__() special method, respectively, instead of __getitem__().

>>> colors = ['red', 'blue', 'green', 'black']
>>> colors[3] = 'white'  # 인덱스 위치에 항목 설정
>>> colors
['red', 'blue', 'green', 'white']
>>> del colors[3]  # 인덱스 3의 항목 삭제
>>> colors
['red', 'blue', 'green']

다음 섹션에 설명된 모든 고급 형태의 서브스크립트 를 할당 및 삭제 시에도 사용할 수 있습니다.

6.3.2.1. 슬라이싱(Slicings)

A more advanced form of subscription, slicing, is commonly used to extract a portion of a sequence. In this form, the subscript is a slice: up to three expressions separated by colons. Any of the expressions may be omitted, but a slice must contain at least one colon:

>>> number_names = ['zero', 'one', 'two', 'three', 'four', 'five']
>>> number_names[1:3]
['one', 'two']
>>> number_names[1:]
['one', 'two', 'three', 'four', 'five']
>>> number_names[:3]
['zero', 'one', 'two']
>>> number_names[:]
['zero', 'one', 'two', 'three', 'four', 'five']
>>> number_names[::2]
['zero', 'two', 'four']
>>> number_names[:-3]
['zero', 'one', 'two']
>>> del number_names[4:]
>>> number_names
['zero', 'one', 'two', 'three']

When a slice is evaluated, the interpreter constructs a slice object whose start, stop and step attributes, respectively, are the results of the expressions between the colons. Any missing expression evaluates to None. This slice object is then passed to the __getitem__() or __class_getitem__() special method, as above.

# 위에서 정의한 SubscriptionDemo 인스턴스를 계속 사용하여:

6.3.2.2. 쉼표로 구분된 서브스크립트

서브스크립트는 두 개 이상의 쉼표로 구분된 표현식 또는 슬라이스로 제공될 수도 있습니다:

# 위에서 정의한 SubscriptionDemo 인스턴스를 사용하여 계속합니다:
>>> demo[1, 2, 3]
subscripted with: (1, 2, 3)
>>> demo[1:2, 3]
subscripted with: (slice(1, 2, None), 3)

This form is commonly used with numerical libraries for slicing multi-dimensional data. In this case, the interpreter constructs a tuple of the results of the expressions or slices, and passes this tuple to the __getitem__() or __class_getitem__() special method, as above.

서브스크립트는 단일 요소 튜플을 지정하기 위해 쉼표 뒤에 오는 단일 표현식 또는 슬라이스로도 제공될 수 있습니다:

>>> demo['spam',]
subscripted with: ('spam',)

6.3.2.3. “별표(Starred)” 서브스크립션

Added in version 3.11: tuple_slices 내의 표현식은 별표가 붙을 수 있습니다. PEP 646 을 참조하십시오.

서브스크립트는 별표가 붙은 표현식을 포함할 수도 있습니다. 이 경우 인터프리터는 결과를 튜플로 언패킹하고, 이 튜플을 __getitem__() 또는 __class_getitem__() 으로 전달합니다:

# 위에서 정의한 SubscriptionDemo 인스턴스를 사용하여 계속합니다:
>>> demo[*range(10)]
subscripted with: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

별표가 붙은 표현식은 쉼표로 구분된 표현식 및 슬라이스와 결합될 수 있습니다:

>>> demo['a', 'b', *range(3), 'c']
subscripted with: ('a', 'b', 0, 1, 2, 'c')

6.3.2.4. 형식적인 서브스크립션 문법

subscription:     primary '[' subscript ']'
subscript:        single_subscript | tuple_subscript
single_subscript: proper_slice | assignment_expression
proper_slice:     [expression] ":" [expression] [ ":" [expression] ]
tuple_subscript:  ','.(single_subscript | starred_expression)+ [',']

| 연산자가 denotes ordered choice 을 상기하십시오. 구체적으로, subscript 에서 두 대안이 모두 일치하는 경우 첫 번째 것(single_subscript)이 우선권을 가집니다.

6.3.3. 호출

호출은 콜러블 객체 (예를 들어, 함수) 를 빌 수도 있는 인자 들의 목록으로 호출합니다.

call:                 primary "(" [argument_list [","] | comprehension] ")"
argument_list:        positional_arguments ["," starred_and_keywords]
                        ["," keywords_arguments]
                      | starred_and_keywords ["," keywords_arguments]
                      | keywords_arguments
positional_arguments: positional_item ("," positional_item)*
positional_item:      assignment_expression | "*" expression
starred_and_keywords: ("*" expression | keyword_item)
                      ("," "*" expression | "," keyword_item)*
keywords_arguments:   (keyword_item | "**" expression)
                      ("," keyword_item | "," "**" expression)*
keyword_item:         identifier "=" expression

생략할 수 있는 마지막 쉼표가 위치나 키워드 인자 뒤에 나타날 수 있지만, 의미를 바꾸지 않습니다.

The primary must evaluate to a callable object (user-defined functions, built-in functions, methods of built-in objects, class objects, methods of class instances, and all objects having a __call__() method are callable). All argument expressions are evaluated before the call is attempted. Please refer to section 함수 정의 for the syntax of formal parameter lists.

키워드 인자가 있는 경우, 다음과 같이 먼저 위치 인자로 변환됩니다. 우선, 형식 매개변수를 위한 빈 슬롯 목록이 생성됩니다. N개의 위치 인자가 있으면 첫 N개의 슬롯에 배치됩니다. 다음으로 각 키워드 인자에 대해 식별자를 사용하여 해당 슬롯을 결정합니다(식별자가 첫 번째 형식 매개변수 이름과 동일하면 첫 번째 슬롯을 사용하고, 이와 같이 진행합니다). 만약 슬롯이 이미 채워져 있다면 TypeError 예외가 발생합니다. 그렇지 않으면 인자가 슬롯에 배치되어 이를 채웁니다(표현식이 None 인 경우에도 슬롯을 채웁니다). 모든 인자가 처리되면 여전히 비어 있는 슬롯은 함수 정의의 해당 기본값으로 채워집니다.(기본값은 함수가 정의될 때 한 번만 계산되므로, 기본값으로 사용되는 리스트나 딕셔너리와 같은 가변 객체는 해당 슬롯에 대한 인자 값을 명시하지 않는 모든 호출에서 공유됩니다. 이는 일반적으로 피해야 합니다.) 기본값이 지정되지 않은 채 비어 있는 슬롯이 있다면 TypeError 예외가 발생합니다. 그렇지 않으면 채워진 슬롯의 목록이 호출을 위한 인수 목록으로 사용됩니다.

구현은 위치 매개변수가 이름을 갖지 않아서, 설사 문서화의 목적으로 이름이 붙여졌다 하더라도, 키워드로 공급될 수 없는 내장 함수들을 제공할 수 있습니다. CPython 에서, 인자들을 파싱하기 위해 PyArg_ParseTuple() 를 사용하는 C로 구현된 함수들이 이 경우입니다.

형식 매개변수 슬롯들보다 많은 위치 인자들이 있으면, *identifier 문법을 사용하는 형식 매개변수가 있지 않은 한, TypeError 예외를 일으킵니다; 이 경우, 그 형식 매개변수는 남는 위치 인자들을 포함하는 튜플을 전달받습니다 (또는 남는 위치 인자들이 없으면 빈 튜플).

키워드 인자가 형식 매개변수 이름에 대응하지 않으면, **identifier 문법을 사용하는 형식 매개변수가 있지 않은 한, TypeError 예외를 일으킵니다; 이 경우, 그 형식 매개변수는 남는 키워드 인자들을 포함하는 딕셔너리나, 남는 위치기반 인자들이 없으면 빈 (새) 딕셔너리를 전달받습니다.

문법 *expression 이 함수 호출에 등장하면, expression 의 값은 이터러블 이 되어야 합니다. 이 이터러블의 요소들은, 그것들이 추가의 위치 인자들인 것처럼 취급됩니다. 호출 f(x1, x2, *y, x3, x4) 의 경우, y 의 값을 구할 때 시퀀스 y1, …, yM 이 나온다면, 이것은 M+4개의 위치 인자들 x1, x2, y1, …, yM, x3, x4 로 호출하는 것과 동등합니다.

이로 인한 결과는 설사 *expression 문법이 명시적인 키워드 인자 뒤에 나올 수는 있어도, 키워드 인자 (그리고 모든 **expression 인자들 – 아래를 보라) 전에 처리된다는 것입니다. 그래서:

>>> def f(a, b):
...     print(a, b)
...
>>> f(b=1, *(2,))
2 1
>>> f(a=1, *(2,))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() got multiple values for keyword argument 'a'
>>> f(1, *(2,))
1 2

동일한 호출에서 키워드 인자와 *expression 문법이 함께 사용되는 것은 드문 경우이므로, 실제로는 이러한 혼동이 자주 발생하지 않습니다.

함수 호출에 **expression 구문이 나타나면, expression 은 추가적인 키워드 인자로 취급되는 내용의 mapping 으로 평가되어야 합니다. 키와 일치하는 매개변수가 이미 값(명시적 키워드 인자 또는 다른 언패킹을 통해)을 부여받은 경우 TypeError 예외가 발생합니다.

**expression``이 사용될 때, 매핑의 키는 문자열이어야 합니다. 매핑의 값은 키와 이름이 동일하고 키워드 할당이 가능한 번째 형식 매개변수에 할당됩니다. 키가 반드시 파이썬 식별자일 필요는 없습니다(예를 들어 ``"max-temp °F"``도 허용되지만, 선언될 있는 어떤 형식 매개변수와도 일치하지 않을 있습니다). 형식 매개변수와 일치하는 것이 없으면 해당 키-값 쌍은 (존재한다면) ``** 매개변수에 의해 수집되며, 없다면 TypeError 예외가 발생합니다.

문법 *identifier 이나 **identifier 를 사용하는 형식 매개변수들은 위치 인자 슬롯이나 키워드 인자 아름들로 사용될 수 없습니다.

버전 3.5에서 변경: 함수 호출은 임의의 개수의 * and ** 언 패킹을 받아들이고, 위치 인자들이 이터러블 언 패킹 (*) 뒤에 올 수 있고, 키워드 인자가 딕셔너리 언 패킹 (**) 뒤에 올 수 있습니다. 최초로 PEP 448 에서 제안되었습니다.

호출은 예외를 일으키지 않는 한, 항상 어떤 값을 돌려줍니다, None 일 수 있습니다. 이 값이 어떻게 계산되는지는 콜러블 객체의 형에 달려있습니다.

만약 그것이—

사용자 정의 함수면:

함수의 코드 블록이 실행되면서 인자 목록이 전달됩니다. 코드 블록이 가장 먼저 하는 일은 형식 매개변수를 인자에 바인딩하는 것입니다; 이는 함수 정의 섹션에 설명되어 있습니다. 코드 블록이 return 문을 실행하면, 해당 값이 함수 호출의 반환 값이 됩니다. return 문을 실행하지 않고 코드 블록의 끝에 도달하면 반환 값은 None 입니다.

내장 함수나 메서드면:

결과는 인터프리터에 달려있습니다; 내장 함수와 메서드들에 대한 설명은 내장 함수 를 보세요.

클래스 객체면:

그 클래스의 새 인스턴스가 반환됩니다.

클래스 인스턴스 메서드면:

대응하는 사용자 정의 함수가 호출되는데, 그 인스턴스가 첫 번째 인자가 되는 하나만큼 더 긴 인자 목록이 전달됩니다.

클래스 인스턴스면:

클래스는 __call__() 메서드를 정의해야 하며, 이 경우 해당 메서드가 호출된 것과 동일한 효과가 발생합니다.

6.4. 어웨이트 표현식

어웨이터블 에서 코루틴 의 실행을 일시 중지합니다. 오직 코루틴 함수 에서만 사용할 수 있습니다.

await_expr: "await" primary

Added in version 3.5.

6.5. 거듭제곱 연산자

거듭제곱 연산자는 그것의 왼쪽에 붙는 일 항 연산자보다 더 강하게 결합합니다; 그것의 오른쪽에 붙는 일 항 연산자보다는 약하게 결합합니다. 문법은 이렇습니다:

power: (await_expr | primary) ["**" u_expr]

그래서, 괄호가 없는 거듭제곱과 일 항 연산자의 시퀀스에서, 연산자는 오른쪽에서 왼쪽으로 값이 구해집니다 (이것이 피연산자의 값을 구하는 순서를 제약하는 것은 아닙니다): -1**2-1 이 됩니다.

거듭제곱 연산자는 두 개의 인자로 호출될 때 내장 pow() 함수와 동일한 의미를 가집니다. 즉, 왼쪽 인자를 오른쪽 인자의 거듭제곱만큼 올린 값을 반환합니다. 숫자 인자들은 먼저 공통 타입으로 변환되며, 결과는 해당 타입이 됩니다.

int 피연산자의 경우, 두 번째 인자가 음수가 아닌 이상 결과는 피연산자들과 같은 형을 갖습니다; 두 번째 인자가 음수면, 모든 인자는 float로 변환되고, float 결과가 전달됩니다. 예를 들어, 10**2100 를 돌려주지만, 10**-20.01 를 돌려줍니다.

0.0 를 음수로 거듭제곱하면 ZeroDivisionError 를 일으킵니다. 음수를 분수로 거듭제곱하면 복소수(complex)가 나옵니다. (예전 버전에서는 ValueError 를 일으켰습니다.)

이 연산은 특별한 __pow__()__rpow__() 메서드를 사용하여 커스터마이징할 수 있습니다.

6.6. 일 항 산술과 비트 연산

모든 일 항 산술과 비트 연산자는 같은 우선순위를 갖습니다.

u_expr: power | "-" u_expr | "+" u_expr | "~" u_expr

단항 - (마이너스) 연산자는 숫자 인자의 부호를 반전시킨 값을 반환하며, 이 연산은 __neg__() 특수 메서드로 재정의할 수 있습니다.

단항 + (플러스) 연산자는 숫자 인자를 그대로 반환하며, 이 연산은 __pos__() 특수 메서드로 재정의할 수 있습니다.

단항 ~ (반전) 연산자는 정수 인자의 비트 반전 값을 반환합니다. x 의 비트 반전은 -(x+1) 으로 정의됩니다. 이 연산은 정수 또는 __invert__() 특수 메서드를 재정의한 사용자 정의 객체에만 적용됩니다.

세 가지 경우 모두, 인자가 올바른 형을 갖지 않는다면, TypeError 예외가 발생합니다.

6.7. 이항 산술 연산

이항 산술 연산자는 관습적인 우선순위를 갖습니다. 이 연산자 중 일부는 일부 비 숫자 형에도 적용됨에 주의해야 합니다. 거듭제곱 연산자와는 별개로, 오직 두 가지 수준만 있는데, 하나는 곱셈형 연산자들이고, 하나는 덧셈형 연산자들입니다.

m_expr: u_expr | m_expr "*" u_expr | m_expr "@" m_expr |
        m_expr "//" u_expr | m_expr "/" u_expr |
        m_expr "%" u_expr
a_expr: m_expr | a_expr "+" m_expr | a_expr "-" m_expr

* (곱셈) 연산자는 인자들의 곱을 반환합니다. 인자는 둘 다 숫자이거나, 하나는 정수이고 다른 하나는 시퀀스여야 합니다. 전자의 경우, 수치들은 공통 실수 타입으로 변환되고 서로 곱해집니다. 후자의 경우, 시퀀스 반복이 수행되며 음수의 반복 횟수는 빈 시퀀스를 반환합니다.

이 연산은 특별한 __mul__()__rmul__() 메서드를 사용하여 커스터마이징할 수 있습니다.

버전 3.14에서 변경: 피연산자 중 하나만 복소수인 경우, 다른 피연산자는 부동 소수점 숫자로 변환됩니다.

@ (at) 연산자는 행렬 곱셈에 사용하려는 것입니다. 파이썬의 내장형들 어느 것도 이 연산자를 구현하지 않습니다.

이 연산은 특별한 __matmul__()__rmatmul__() 메서드를 사용하여 커스터마이징할 수 있습니다.

Added in version 3.5.

/ (나눗셈) 및 // (바닥 나눗셈, floor division) 연산자는 인자들의 몫을 반환합니다. 숫자 인자들은 먼저 공통 타입으로 변환되며, 정수의 나눗셈은 실수를 생성하고, 정수의 바닥 나눗셈은 정수를 결과로 합니다. 이때 바닥 나눗셈의 결과는 수학적 나눗셈에 ‘floor’ 함수를 적용한 것과 같습니다. 0으로 나누는 경우 ZeroDivisionError 예외가 발생합니다.

나눗셈 연산은 특별한 __truediv__()__rtruediv__() 메서드를 사용하여 커스터마이징할 수 있습니다. 바닥 나눗셈 연산은 특별한 __floordiv__()__rfloordiv__() 메서드를 사용하여 커스터마이징할 수 있습니다.

% (나머지) 연산자는 첫 번째 인자를 두 번째 인자로 나눈 나머지를 산출합니다. 숫자 인자들은 먼저 공통 형식 으로 변환됩니다. 오른쪽 인자가 0이면 ZeroDivisionError 예외가 발생합니다. 인자들은 부동 소수점 숫자가 될 수 있습니다. 예를 들어, 3.14%0.70.34 와 같습니다 (3.144*0.7 + 0.34 와 같기 때문에). 나머지 연산자는 항상 두 번째 피연산자와 같은 부호(또는 0)를 가진 결과를 산출하며, 결과의 절대값은 두 번째 피연산자의 절대값보다 엄격하게 작습니다 [1].

정수 나눗셈과 모듈로 연산자는 다음과 같은 항등식으로 연결되어 있습니다: x == (x//y)*y + (x%y). 정수 나눗셈과 모듈로는 내장 함수 divmod() 와도 연결되어 있습니다: divmod(x, y) == (x//y, x%y). [2].

숫자들에 대해 모듈로 연산을 수행하는 것에 더해, % 연산자는 예전 스타일의 문자열 포매팅 (인터폴레이션이라고도 알려져 있습니다)을 수행하기 위해 문자열 객체에 의해 다시 정의됩니다. 문자열 포매팅의 문법은 파이썬 라이브러리 레퍼런스의 섹션 printf 스타일 문자열 포매팅 에서 설명합니다.

나머지(modulo) 연산은 특별한 __mod__()__rmod__() 메서드를 사용하여 커스터마이징할 수 있습니다.

바닥 나눗셈 연산자, 나머지 연산자, 그리고 divmod() 함수는 복소수에 대해 정의되지 않습니다. 대신 적절한 경우 abs() 함수를 사용하여 부동 소수점 숫자로 변환하십시오.

+ (덧셈) 연산자는 인자들의 합을 반환합니다. 인자는 둘 다 수이거나, 둘 다 동일한 타입의 시퀀스여야 합니다. 전자의 경우, 수들은 공통 실수 타입으로 변환된 후 서로 더해지며, 후자의 경우 시퀀스가 연결됩니다.

이 연산은 특별한 __add__()__radd__() 메서드를 사용하여 커스터마이징할 수 있습니다.

버전 3.14에서 변경: 피연산자 중 하나만 복소수인 경우, 다른 피연산자는 부동 소수점 숫자로 변환됩니다.

- (뺄셈) 연산자는 인자들의 차를 반환합니다. 숫자 인자들은 먼저 공통 실수 타입으로 변환됩니다.

이 연산은 특별한 __sub__()__rsub__() 메서드를 사용하여 커스터마이징할 수 있습니다.

버전 3.14에서 변경: 피연산자 중 하나만 복소수인 경우, 다른 피연산자는 부동 소수점 숫자로 변환됩니다.

6.8. 시프트 연산

시프트 연산은 산술 연산보다 낮은 우선순위를 갖습니다.

shift_expr: a_expr | shift_expr ("<<" | ">>") a_expr

이 연산들은 정수들을 인자로 받아들입니다. 첫 번째 인자를 두 번째 인자로 주어진 비트 수만큼 왼쪽이나 오른쪽으로 밉니다(shift).

왼쪽 시프트 연산은 특별한 __lshift__()__rlshift__() 메서드를 사용하여 커스터마이징할 수 있습니다. 오른쪽 시프트 연산은 특별한 __rshift__()__rrshift__() 메서드를 사용하여 커스터마이징할 수 있습니다.

오른쪽으로 n 비트 시프트 하는 것은 pow(2,n) 로 정수 나눗셈하는 것으로 정의됩니다. 왼쪽으로 n 비트 시프트 하는 것은 pow(2,n) 를 곱하는 것으로 정의됩니다.

6.9. 이항 비트 연산

세 개의 비트 연산은 각기 다른 우선순위를 갖습니다:

and_expr: shift_expr | and_expr "&" shift_expr
xor_expr: and_expr | xor_expr "^" and_expr
or_expr:  xor_expr | or_expr "|" xor_expr

& 연산자는 인자들의 비트 단위 AND를 반환하며, 이때 인자는 정수여야 하거나 둘 중 하나는 __and__() 또는 __rand__() 특수 메서드를 재정의한 사용자 정의 객체여야 합니다.

^ 연산자는 인자들의 비트 단위 XOR(배타적 OR)를 반환하며, 이때 인자는 정수여야 하거나 둘 중 하나는 __xor__() 또는 __rxor__() 특수 메서드를 재정의한 사용자 정의 객체여여야 합니다.

| 연산자는 인자들의 비트 단위(포함적) OR를 반환하며, 이때 인자는 정수여야 하거나 둘 중 하나는 __or__() 또는 __ror__() 특수 메서드를 재정의한 사용자 정의 객체여야 합니다.

6.10. 비교

C와는 달리, 파이썬에서 모든 비교 연산은 같은 우선순위를 갖는데, 산술, 시프팅, 비트 연산들보다 낮습니다. 또한, C와는 달리, a < b < c 와 같은 표현식이 수학에서와 같은 방식으로 해석됩니다.

comparison:    or_expr (comp_operator or_expr)*
comp_operator: "<" | ">" | "==" | ">=" | "<=" | "!="
               | "is" ["not"] | ["not"] "in"

비교는 True 또는 False 와 같은 불리언 값을 반환합니다. 사용자 정의한 rich comparison methods 는 비-불리언 값을 반환할 수 있으며, 이 경우 파이썬은 불리언 문맥에서 해당 값에 대해 bool() 을 호출합니다.

비교는 자유롭게 연결될 수 있습니다, 예를 들어, x < y <= zx < y and y <= z 와 동등한데, 차이점은 y 의 값을 오직 한 번만 구한다는 것입니다 (하지만 두 경우 모두 x < y 가 거짓이면 z 의 값은 구하지 않습니다).

형식적으로, a, b, c, …, y, z 가 표현식이고, op1, op2, …, opN 가 비교 연산자면, a op1 b op2 c ... y opN z 는 각 표현식의 값을 최대 한 번만 구한다는 점을 제외하고는 a op1 b and b op2 c and ... y opN z 와 동등합니다.

a op1 b op2 cac 간의 어떤 종류의 비교도 암시하지 않기 때문에, 예를 들어, x < y > z 이 완벽하게 (아마 이쁘지는 않더라도) 올바르다는 것에 주의해야 합니다.

6.10.1. 값 비교

연산자 <, >, ==, >=, <=, != 는 두 객체의 값을 비교합니다. 객체들이 같은 형일 필요는 없습니다.

객체, 값, 형 장은 객체들이 (형과 아이덴티티에 더해) 값을 갖는다고 말하고 있습니다. 파이썬에서 객체의 값은 좀 추상적인 개념입니다: 예를 들어, 객체의 값에 대한 규범적인(canonical) 액세스 방법은 없습니다. 또한, 객체의 값이 특별한 방식(예를 들어, 모든 데이터 어트리뷰트로 구성되는 것)으로 구성되어야 한다는 요구 사항도 없습니다. 비교 연산자는 객체의 값이 무엇인지에 대한 특정한 종류의 개념을 구현합니다. 객체의 값을 비교를 통해 간접적으로 정의한다고 생각해도 좋습니다.

모든 타입은 (직접 또는 간접적으로) object 의 서브타입이기 때문에, object 로부터 기본 비교 동작을 상속합니다. 유형은 기본적인 커스터마이제이션 에서 설명하는 __lt__() 와 같은 rich comparison methods 를 구현하여 비교 동작을 커스터마이징할 수 있습니다.

동등 비교 (==!=) 의 기본 동작은 객체의 아이덴티티에 기반을 둡니다. 그래서, 같은 아이덴티티를 갖는 인스턴스 간의 동등 비교는 같음을 주고, 다른 아이덴티티를 갖는 인스턴스 간의 동등 비교는 다름을 줍니다. 이 기본 동작의 동기는 모든 객체가 반사적(reflexive) (즉, x is yx == y 를 암시합니다) 이도록 만들고자 하는 욕구입니다.

기본 대소 비교(order comparison) (<, >, <=, >=) 는 제공되지 않습니다; 시도하면 TypeError 를 일으킵니다. 이 기본 동작의 동기는 동등함과 유사한 항등 관계가 없다는 것입니다.

다른 아이덴티티를 갖는 인스턴스들이 항상 서로 다르다는, 기본 동등 비교의 동작은, 객체의 값과 값 기반의 동등함에 대한 나름의 정의를 가진 형들이 필요로 하는 것과는 크게 다를 수 있습니다. 그런 형들은 자신의 비교 동작을 커스터마이즈 할 필요가 있고, 사실 많은 내장형이 그렇게 하고 있습니다.

다음 목록은 가장 중요한 내장형들의 비교 동작을 기술합니다.

  • 내장 숫자 형 ((숫자 형 — int, float, complex)) 과 표준 라이브러리 형 fractions.Fractiondecimal.Decimal 에 속하는 숫자들은, 복소수가 대소 비교를 지원하지 않는다는 제약 사항만 빼고는, 같거나 다른 형들 간의 비교가 가능합니다. 관련된 형들의 한계 안에서, 정밀도의 손실 없이 수학적으로 (알고리즘 적으로) 올바르게 비교합니다.

    NaN(not-a-number) 값들 float('NaN')decimal.Decimal('NaN')은 특별합니다. 모든 숫자와 NaN 간의 비교는 거짓입니다. 반 직관적으로 내포하고 있는 것은, NaN 이 자신과 같지 않다는 것입니다. 예를 들어, x = float('NaN'), 3 < x, x < 3x == x는 모두 거짓이지만, x != x는 참입니다. 이 동작은 IEEE 754를 준수합니다.

  • NoneNotImplemented 은 싱글톤입니다. PEP 8 에서는 싱글톤에 대한 비교를 수행할 때 항상 is 또는 is not 을 사용해야 하며, 절대 동등성 연산자를 사용해서는 안 된다고 권고합니다.

  • 바이너리 시퀀스들 (bytesbytearray 의 인스턴스들)은 형을 건너 상호 비교될 수 있습니다. 이것들은 요소들의 숫자 값을 사용해서 사전식으로(lexicographically) 비교합니다.

  • 문자열들 (str 의 인스턴스들) 은 문자들의 유니코드 코드 포인트(Unicode code points) (내장 함수 ord() 의 결과)를 사용해서 사전식으로 비교합니다. [3]

    문자열과 바이너리 시퀀스는 직접 비교할 수 없습니다.

  • 시퀀스들 (tuple, list, range 의 인스턴스들)은 같은 형끼리 비교될 수 있는데, range는 대소 비교를 지원하지 않습니다. 서로 다른 형들 간의 동등 비교는 다름을 주고, 서로 다른 형들 간의 대소 비교는 TypeError 를 일으킵니다.

    시퀀스는 대응하는 요소 간의 비교를 사용해서 사전적으로 비교합니다. 내장 컨테이너는 일반적으로 동일한(identical) 객체가 자신과 같다고(equal) 가정합니다. 이를 통해 동일한 객체에 대한 동등성(equality) 검사를 우회하여 성능을 개선하고 내부 불변성을 유지합니다.

    내장 컬렉션들의 사전적인 비교는 다음과 같이 이루어집니다:

    • 두 컬렉션이 같다고 비교되기 위해서는, 같은 형이고, 길이가 같고, 대응하는 요소들의 각 쌍이 같다고 비교되어야 합니다 (예를 들어, [1,2] == (1,2) 는 거짓인데, 형이 다르기 때문입니다).

    • 대소 비교를 지원하는 컬렉션들은 첫 번째로 다른 요소들과 같은 순서를 줍니다 (예를 들어, [1,2,x] <= [1,2,y]x <= y 와 같은 값입니다). 대응하는 요소가 없는 경우 더 짧은 컬렉션이 작다고 비교됩니다 (예를 들어, [1,2] < [1,2,3] 은 참입니다).

  • 매핑(dict`의 인스턴스)은 오직 동일한 ``(key, value)` 쌍을 가질 때만 동등한 것으로 비교됩니다. 키와 값의 동등성 비교는 반사성을 보장합니다.

    대소 비교 (<, >, <=, >=) 는 TypeError 를 일으킵니다.

  • 집합들 (set 이나 frozenset 의 인스턴스들)은 같은 형들과 서로 다른 형들 간에 비교될 수 있습니다.

    이것들은 부분집합(subset)과 상위집합(superset)을 뜻하는 대소비교 연산자들을 정의합니다. 이 관계는 전 순서(total ordering)를 정의하지 않습니다 (예를 들어, 두 집합 {1,2}{2,3} 는 다르면서도, 하나가 다른 하나의 부분집합이지도, 하나가 다른 하나의 상위집합이지도 않습니다). 따라서, 전 순서에 의존하는 함수의 인자로는 적합하지 않습니다 (예를 들어, min(), max(), sorted() 에 입력으로 집합의 리스트를 제공하면 정의되지 않은 결과를 줍니다).

    집합의 비교는 그 요소들의 반사성을 강제합니다.

  • 대부분의 다른 내장형들은 비교 메서드들을 구현하지 않기 때문에, 기본 비교 동작을 계승합니다.

비교 동작을 커스터마이즈하는 사용자 정의 클래스들은 가능하다면 몇 가지 일관성 규칙을 준수해야 합니다:

  • 동등 비교는 반사적(reflexive)이어야 합니다. 다른 말로 표현하면, 아이덴티티가 같은 객체는 같다고 비교되어야 합니다:

    x is yx == y 다.

  • 비교는 대칭적(symmetric)이어야 합니다. 다른 말로 표현하면, 다음과 같은 표현식은 같은 결과를 주어야 합니다:

    x == yy == x

    x != yy != x

    x < yy > x

    x <= yy >= x

  • 비교는 추이적(transitive)이어야 합니다. 다음 (철저하지 않은) 예들이 이것을 예증합니다:

    x > y and y > zx > z

    x < y and y <= zx < z

  • 역 비교는 논리적 부정이 되어야 합니다. 다른 말로 표현하면, 다음 표현식들이 같은 값을 주어야 합니다:

    x == ynot x != y

    x < ynot x >= y (전 순서의 경우)

    x > ynot x <= y (전 순서의 경우)

    마지막 두 표현식은 전 순서 컬렉션(예를 들어 시퀀스에는 적용되지만, 집합이나 매핑에는 적용되지 않음)에 적용됩니다. 또한 @~functools.total_ordering 데코레이터를 참조하십시오.

  • hash() 결과는 동등성과 일관성을 유지해야 합니다. 같은 객체들은 같은 해시값을 같거나 해시 불가능으로 지정되어야 합니다.

파이썬은 이 일관성 규칙들을 강제하지 않습니다. 사실 NaN 값들은 이 규칙을 따르지 않는 예입니다.

6.10.2. 멤버십 검사 연산

연산자 innot in 은 멤버십을 검사합니다. x in sxs 의 멤버일 때 True 를, 그렇지 않을 때 False 를 줍니다. x not in sx in s 의 부정을 줍니다. 딕셔너리 뿐만 아니라 모든 내장 시퀀스들과 집합 형들이 이것을 지원하는데, 딕셔너리의 경우는 in 이 딕셔너리에 주어진 키가 있는지 검사합니다. list, tuple, set, frozenset, dict, collections.deque 와 같은 컨테이너형들의 경우, 표현식 x in yany(x is e or x == e for e in y) 와 동등합니다.

문자열과 바이트열 형의 경우, x in yxy 의 부분 문자열(substring)인 경우, 그리고 오직 그 경우만 True 입니다. 동등한 검사는 y.find(x) != -1 입니다. 빈 문자열은 항상 다른 문자열들의 부분 문자열로 취급되기 때문에, "" in "abc"True 를 돌려줍니다.

__contains__() 메서드를 정의하는 사용자 정의 클래스의 경우, y.__contains__(x) 가 참을 반환하면 x in yTrue 를 반환하고, 그렇지 않으면 False 를 반환합니다.

__contains__() 은 정의하지 않지만 __iter__() 를 정의하는 사용자 정의 클래스의 경우, y 를 반복(iterate)하는 동안 x is z or x == z 표현식이 참이 되는 어떤 값 z 가 생성되면 x in yTrue 가 됩니다. 반복 중에 예외가 발생하면, 이는 마치 in 이 해당 예외를 발생시킨 것과 동일하게 처리됩니다.

마지막으로 이전 스타일의 반복 프로토콜이 시도됩니다: 클래스가 __getitem__() 를 정의하는 경우, x is y[i] or x == y[i] 가 성립하며 더 낮은 정수 인덱스에서 IndexError 예외가 발생하지 않는 비음수 정수 인덱스 i 가 존재할 때만 x in yTrue 입니다. (다른 예외가 발생하면, 이는 마치 in 이 해당 예외를 발생시킨 것과 동일하게 처리됩니다.)

연산자 not inin 의 논리적 부정으로 정의됩니다.

6.10.3. 아이덴티티 비교

연산자 isis not 은 객체의 아이덴티티를 검사합니다: x is yxy 가 아이덴티티가 같은 객체일 때, 그리고 오직 그 경우만 참입니다. 객체의 아이덴티티는 id() 함수를 사용해서 결정됩니다. x is not y 은 논리적 부정 값을 줍니다. [4]

6.11. 논리 연산(Boolean operations)

or_test:  and_test | or_test "or" and_test
and_test: not_test | and_test "and" not_test
not_test: comparison | "not" not_test

Boolean 연산의 문맥이나 제어 흐름 문에서 표현식이 사용될 때, 다음과 같은 값들은 거짓(false)으로 해석됩니다: False, None, 모든 수치형 타입의 0, 그리고 빈 문자열 및 컨테이너(문자열, 튜플, 리스트, 딕셔너리, 집합 및 frozenset 포함). 그 외의 모든 값은 참(true)으로 해석됩니다. 사용자 정의 객체는 __bool__() 메서드를 제공함으로써 자신의 진릿값(truth value)을 사용자 정의할 수 있습니다.

연산자 not 은 그 인자가 거짓이면 True 를, 그렇지 않으면 False 를 줍니다.

표현식 x and y 는 먼저 x 의 값을 구합니다; x 가 거짓이면 그 값을 돌려줍니다; 그렇지 않으면 y 의 값을 구한 후에 그 결과를 돌려줍니다.

표현식 x or y 는 먼저 x 의 값을 구합니다; x 가 참이면 그 값을 돌려줍니다. 그렇지 않으면 y 의 값을 구한 후에 그 결과를 돌려줍니다.

andor 어느 것도 반환 값이나 그 형을 FalseTrue 로 제한하지 않고, 대신 마지막에 값이 구해진 인자를 돌려줌에 주의해야 합니다. 이것은 때로 쓸모가 있습니다, 예를 들어 s 가 문자열이고 비어 있으면 기본값으로 대체되어야 한다면, 표현식 s or 'foo' 는 원하는 값을 제공합니다. not 은 새 값을 만들어야 하므로, 그 인자의 형과 관계없이 논리값(boolean value)을 돌려줍니다 (예를 들어, not 'foo''' 가 아니라 False 를 만듭니다.)

6.12. 대입 표현식

assignment_expression: [identifier ":="] expression

An assignment expression (sometimes also called a “named expression” or “walrus”) assigns an expression to an identifier, while also returning the value of the expression.

일반적인 사용 사례 중 하나는 일치하는 정규식을 처리할 때입니다:

if matching := pattern.search(data):
    do_something(matching)

또는, 청크로 파일 스트림을 처리할 때:

while chunk := file.read(9000):
    process(chunk)

대입 표현식은 표현식 문으로 사용될 때, 그리고 슬라이싱, 조건부(conditional), lambda, 키워드 인자(keyword-argument), 컴프리헨션-if(comprehension-if) 표현식이나 assert, with, assignment 문에서 하위 표현식으로 사용될 때 괄호로 둘러싸여야 합니다. 그 외의 모든 사용 가능한 위치에서는 ifwhile 문을 포함하여 괄호가 필요하지 않습니다.

Added in version 3.8: 대입 표현식에 대한 더 자세한 내용은 PEP 572를 참조하세요.

6.13. 조건 표현식(Conditional expressions)

conditional_expression: or_test ["if" or_test "else" expression]
expression:             conditional_expression | lambda_expr

조건부 표현식(때때로

표현식 x if C else y 은 먼저 x 대신에 조건 C 의 값을 구합니다. C 가 참이면, x 의 값이 구해지고 그 값을 돌려줍니다; 그렇지 않으면, y 의 값을 구한 후에 그 결과를 돌려줍니다.

조건 표현식에 대한 더 자세한 내용은 PEP 308 를 참조하세요.

6.14. 람다(Lambdas)

lambda_expr: "lambda" [parameter_list] ":" expression

람다 표현식은 (때로 람다 형식(lambda forms)이라고 불립니다) 이름 없는 함수를 만드는 데 사용됩니다. 표현식 lambda parameters: expression 는 함수 객체를 줍니다. 이 이름 없는 객체는 이렇게 정의된 함수 객체처럼 동작합니다:

def <lambda>(parameters):
    return expression

매개변수 목록의 문법은 함수 정의 섹션을 보세요. 람다 표현식으로 만들어진 함수는 문장(statements)이나 어노테이션(annotations)을 포함할 수 없음에 주의해야 합니다.

6.15. 표현식 목록(Expression lists)

starred_expression:       "*" or_expr | expression
flexible_expression:      assignment_expression | starred_expression
flexible_expression_list: flexible_expression ("," flexible_expression)* [","]
starred_expression_list:  starred_expression ("," starred_expression)* [","]
expression_list:          expression ("," expression)* [","]
yield_list:               expression_list | starred_expression "," [starred_expression_list]

리스트나 집합 디스플레이의 일부일 때를 제외하고, 최소한 하나의 쉼표를 포함하는 표현식 목록은 튜플을 줍니다. 튜플의 길이는 목록에 있는 표현식의 개수입니다. 표현식들은 왼쪽에서 오른쪽으로 값이 구해집니다.

뒤에 오는 쉼표(trailing comma)는 1,``과 같이 항목이 하나인 튜플을 생성할 때만 필수이며, 다른 모든 경우에는 선택사항입니다. 뒤에 오는 쉼표가 없는 단일 표현식은 튜플을 생성하지 않고 해당 표현식의 값을 반환합니다. (빈 튜플을 생성하려면 괄호를 사용하십시오: ``().)

6.15.1. Iterable 언패킹

표현식 목록 또는 튜플, 리스트나 집합의 표시(display)에서 모든 표현식 앞에 애스터리스크(*)를 붙일 수 있습니다. 이는 iterable unpacking 을 나타냅니다.

실행 시점에 애스터리스크가 붙은 표현식은 반드시 iterable 로 평가되어야 합니다. 해당 iterable은 항목들의 시퀀스로 확장되며, 언패킹이 일어나는 위치의 새 튜플, 리스트 또는 집합에 포함됩니다.

Added in version 3.5: 표현식 목록에서의 이터러블 언 패킹, PEP 448 에서 최초로 제안되었습니다.

Added in version 3.11: 표현식 목록의 모든 항목에 별표(starred)를 붙일 수 있습니다. PEP 646 을 참조하십시오.

6.16. 값을 구하는 순서

파이썬은 왼쪽에서 오른쪽으로 표현식의 값을 구합니다. 대입의 값을 구하는 동안, 우변의 값이 좌변보다 먼저 구해짐에 주목하십시오.

다음 줄들에서, 표현식은 그들의 끝에 붙은 숫자들의 순서대로 값이 구해집니다:

expr1, expr2, expr3, expr4
(expr1, expr2, expr3, expr4)
{expr1: expr2, expr3: expr4}
expr1 + expr2 * (expr3 - expr4)
expr1(expr2, expr3, *expr4, **expr5)
expr3, expr4 = expr1, expr2

6.17. 연산자 우선순위

다음 표는 파이썬의 연산자 우선순위를 높은 순위(가장 강하게 결합)에서 낮은 순위(가장 약하게 결합)로 요약한 것입니다. 같은 상자 안에 있는 연산자들은 동일한 우선순위를 가집니다. 문법이 명시적으로 제공되지 않는 한, 연산자는 이항 연산자입니다. 같은 상자에 속한 연산자들은 왼쪽에서 오른쪽으로 그룹화됩니다(거듭제곱과 조건부 표현식은 오른쪽에서 왼쪽으로 그룹화됨).*

비교, 멤버십 검사, 아이덴티티 검사들은 모두 같은 우선순위를 갖고 비교 섹션에서 설명한 것처럼 왼쪽에서 오른쪽으로 이어붙이기(chaining) 하는 기능을 갖습니다.

연산자

설명

(expressions...),

[expressions...], {key: value...}, {expressions...}

결합(binding) 또는 괄호 친 표현식, 리스트 디스플레이, 딕셔너리 디스플레이, 집합 디스플레이

x[index], x[index:index] x(arguments...), x.attribute

서브스크립션(슬라이싱 포함), 호출, 어트리뷰트 참조

await x

어웨이트 표현식

**

거듭제곱 [5]

+x, -x, ~x

양, 음, 비트 NOT

*, @, /, //, %

곱셈, 행렬 곱셈, 나눗셈, 정수 나눗셈, 나머지 [6]

+, -

덧셈과 뺄셈

<<, >>

시프트

&

비트 AND

^

비트 XOR

|

비트 OR

in, not in, is, is not, <, <=, >, >=, !=, ==

비교, 멤버십 검사와 아이덴티티 검사를 포함합니다

not x

논리 NOT

and

논리 AND

or

논리 OR

ifelse

조건 표현식

lambda

람다 표현식

:=

대입 표현식

각주

분실물 보관소