6. 표현식
6. 표현식 (Expressions)
이 장에서는 Python에서 표현식의 요소들이 의미하는 바를 설명합니다.
구문 표기 참고(Syntax Notes): 이 장과 다음 장들에서는 구문을 설명할 때 어휘 분석(lexical analysis)이 아니라 문법 표기(grammar notation)를 사용할 거예요.
어떤 구문 규칙의 (한 대안이) 다음과 같은 형태일 때:
name: othername
그리고 의미(semantics)가 주어지지 않았다면, 이 형태의 name의 의미는 othername과 동일합니다.
출처: 6. Expressions
본문
6.1. 산술 변환 (Arithmetic conversions)
아래 산술 연산자 설명에서 "숫자 인수가 공통 실수 타입(common real type)으로 변환된다"는 표현은, 내장 수치 타입에 대한 연산자 구현이 표준 라이브러리 문서의 Numeric Types 섹션에서 설명한 대로 동작한다는 뜻이에요.
일부 연산자와 비-숫자 피연산자(예: % 연산자의 왼쪽 인수로 문자열)에는 몇 가지 추가 규칙이 적용돼요. 확장(exntension)은 자신만의 변환 동작을 정의해야 합니다.
6.2. 원자 (Atoms)
원자(atom)는 표현식의 가장 기본적인 요소예요. 가장 단순한 원자는 이름(name)이나 리터럴(literal)이에요. 괄호, 대괄호 또는 중괄호로 둘러싸인 형태들도 문법적으로 원자로 분류됩니다.
형식적으로 원자의 구문은 다음과 같아요:
atom:
| 'True'
| 'False'
| 'None'
| '...'
| identifier
| literal
| enclosure
enclosure:
| parenth_form
| list_display
| dict_display
| set_display
| generator_expression
| yield_atom
6.2.1. 내장 상수 (Built-in constants)
True, False, None 키워드는 내장 상수(built-in constants)를 가리켜요. ... 토큰은 Ellipsis 상수를 가리킵니다.
이런 원자들을 평가하면 해당 값이 나옵니다.
Note
몇몇 내장 상수가 더 전역 변수로 사용 가능하지만, 여기 언급된 것들만 키워드예요. 특히 다음 이름들은 재할당하거나 속성으로 사용할 수 없습니다:
>>> False = 123
File "<input>", line 1
False = 123
^^^^^
SyntaxError: cannot assign to False
6.2.2. 식별자 (Identifiers, 이름 Names)
원자로 나타나는 식별자는 이름이에요. 어휘 정의는 Names (identifiers and keywords) 섹션, 이름 짓기·바인딩 문서는 Naming and binding 섹션을 참조하세요.
이름이 객체에 바인딩되어 있으면, 그 원자를 평가하면 그 객체를 얻어요. 이름이 바인딩되어 있지 않으면, 평가하려고 하면 NameError 예외가 발생합니다.
6.2.2.1. 비공개 이름 변형 (Private name mangling)
클래스 정의에 텍스트로 나타나는 식별자가 밑줄 두 개 이상으로 시작하고 밑줄 두 개 이상으로 끝나지 않으면, 그 클래스의 *비공개 이름(private name)*으로 간주돼요.
See also
클래스 명세(class specifications).
더 정확히 말하면, 코드가 생성되기 전에 비공개 이름은 더 긴 형태로 변환됩니다. 변환된 이름이 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)*은 값의 텍스트 표현이에요. Python은 숫자, 문자열, 바이트 리터럴을 지원해요. 형식 문자열(format strings)과 템플릿 문자열(template strings)은 문자열 리터럴로 취급됩니다.
숫자 리터럴은 하나의 NUMBER 토큰으로 이루어지며, 정수, 부동소수점 수 또는 허수(imaginary number)를 가리켜요. 자세한 내용은 Lexical analysis 문서의 Numeric literals 섹션을 참조하세요.
문자열과 바이트 리터럴은 여러 토큰으로 이루어질 수 있어요. 자세한 내용은 String literal concatenation 섹션을 참조하세요.
-3이나 3+4.2j 같은 음수와 복소수는 문법적으로 리터럴이 아니라 - 또는 + 연산자를 포함한 단항·이항 산술 연산이라는 점에 주의하세요.
리터럴을 평가하면 주어진 값(int, float, complex, str, bytes, 또는 Template)의 객체가 나옵니다. 부동소수점·허수 리터럴의 경우 값이 근사될 수 있어요.
리터럴의 형식 문법은 다음과 같습니다.
literal: strings | NUMBER
6.2.3.1. 리터럴과 객체 정체성 (Literals and object identity)
모든 리터럴은 불변 데이터 타입에 대응하므로, 객체의 정체성(identity)은 값보다 덜 중요해요. 같은 값을 가진 리터럴을 여러 번 평가하면(프로그램 텍스트에서 같은 위치든 다른 위치든) 같은 객체나, 같은 값을 가진 다른 객체를 얻을 수 있습니다.
CPython implementation detail
예를 들어 CPython에서 같은 값을 가진 작은 정수는 같은 객체로 평가됩니다:
>>> 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
자세한 내용은 When can I rely on identity tests with the is operator?를 참조하세요.
템플릿 문자열(template strings)은 불변이지만 Interpolation 값으로 변경 가능한 객체를 참조할 수 있어요. 이 섹션의 목적상, 두 t-문자열의 구조와 값의 정체성이 모두 일치하면 "같은 값"이라고 봅니다.
CPython implementation detail: 현재는 템플릿 문자열을 평가할 때마다 서로 다른 객체가 만들어집니다.
6.2.3.2. 문자열 리터럴 연결 (String literal concatenation)
인접한 여러 문자열 또는 바이트 리터럴은 서로 다른 따옴표 규칙을 사용할 수 있으며, 그 의미는 연결(concatenation)한 것과 같아요:
>>> "hello" 'world'
"helloworld"
이 기능은 문법 수준에서 정의되므로 리터럴에서만 동작해요. 문자열 표현식을 런타임에 연결하려면 + 연산자를 사용할 수 있습니다:
>>> greeting = "Hello"
>>> space = " "
>>> name = "Blaise"
>>> print(greeting + space + name) # not: print(greeting space name)
Hello Blaise
리터럴 연결은 raw 문자열, 삼중 따옴표 문자열, 형식 문자열 리터럴을 자유롭게 섞을 수 있어요. 예를 들어:
>>> "Hello" r', ' f"{name}!"
"Hello, Blaise!"
이 기능은 필요한 백슬래시 수를 줄이거나, 긴 문자열을 여러 줄에 편리하게 나누거나, 문자열 일부에 주석을 추가하는 데 사용할 수 있어요. 예를 들어:
re.compile("[A-Za-z_]” # letter or underscore
"[A-Za-z0-9_]*" # letter, digit or underscore
)
하지만 바이트 리터럴은 다른 바이트 리터럴과만 결합할 수 있고, 어떤 종류의 문자열 리터럴과도 결합할 수 없어요. 또한 템플릿 문자열 리터럴은 다른 템플릿 문자열 리터럴과만 결합할 수 있습니다:
>>> t"Hello" t"{name}!"
Template(strings=('Hello', '!'), interpolations=(...))
형식적으로는:
strings: (STRING | fstring)+ | tstring+
6.2.4. 괄호로 둘러싼 형태 (Parenthesized forms)
괄호로 둘러싼 형태(parenthesized form)는 괄호 안에 들어간 선택적인 표현식 목록이에요:
parenth_form: "(" [starred_expression] ")"
괄호로 둘러싼 표현식 목록은 그 표현식 목록이 산출하는 값을 산출해요. 목록에 쉼표가 하나 이상 있으면 튜플을, 그렇지 않으면 그 표현식 목록을 이루는 단일 표현식을 산출합니다.
빈 괄호 쌍은 빈 튜플 객체를 산출해요. 튜플은 불변이므로 리터럴과 동일한 규칙이 적용됩니다(즉 빈 튜플의 두 번의 출현은 같은 객체를 산출할 수도, 아닐 수도 있어요).
튜플은 괄호가 아니라 쉼표의 사용으로 만들어진다는 점을 기억하세요. 예외는 빈 튜플로, 괄호가 필요합니다 — 괄호 없는 "빈 것"을 표현식에 허용하면 모호함이 생기고 흔한 오타가 잡히지 않고 지나가게 됩니다.
6.2.5. 리스트, 집합, 딕셔너리 표시 (Displays for lists, sets and dictionaries)
리스트, 집합 또는 딕셔너리를 만들기 위해 Python은 "표시(displays)"라고 불리는 특별한 구문을 제공하며, 각 표시에는 두 가지 형태가 있습니다:
컨테이너 내용을 명시적으로 나열하거나,
*컴프리헨션(comprehension)*이라고 불리는 일련의 반복·필터링 명령으로 계산합니다.
컴프리헨션의 공통 구문 요소는 다음과 같아요:
comprehension: assignment_expression comp_for
comp_for: ["async"] "for" target_list "in" or_test [comp_iter]
comp_iter: comp_for | comp_if
comp_if: "if" or_test [comp_iter]
컴프리헨션은 단일 표현식 뒤에 최소 하나의 for 절, 그리고 0개 이상의 for 또는 if 절이 오는 형태예요. 이 경우 새 컨테이너의 요소는 각 for 또는 if 절을 블록으로 간주하고 왼쪽에서 오른쪽으로 중첩하며, 가장 안쪽 블록에 도달할 때마다 표현식을 평가해 요소를 만들어내는 방식으로 산출됩니다.
하지만 가장 왼쪽 for 절의 반복 가능 표현식(iterable expression)을 제외하면, 컴프리헨션은 별도의 암시적 중첩 스코프(implicitly nested scope)에서 실행돼요. 이렇게 하면 대상 목록에 할당된 이름이 바깥 스코프로 "새어 나가지" 않도록 보장합니다.
가장 왼쪽 for 절의 반복 가능 표현식은 바깥 스코프에서 직접 평가된 뒤 암시적 중첩 스코프에 인수로 전달됩니다. 이후의 for 절과 가장 왼쪽 for 절의 필터 조건은 가장 왼쪽 반복 가능 객체에서 얻은 값에 의존할 수 있으므로 바깥 스코프에서 평가할 수 없어요. 예: [x*y for x in range(10) for y in range(x, x+10)].
컴프리헨션이 항상 적절한 타입의 컨테이너를 만들도록 보장하기 위해, yield와 yield from 표현식은 암시적 중첩 스코프에서 금지됩니다.
Python 3.6부터 async def 함수에서 async for 절을 사용해 비동기 반복자(asynchronous iterator)를 반복할 수 있어요. async def 함수의 컴프리헨션은 선행 표현식 다음에 for 또는 async for 절로 구성될 수 있고, 추가 for 또는 async for 절을 포함할 수 있으며, await 표현식도 사용할 수 있습니다.
컴프리헨션이 async for 절을 포함하거나, 가장 왼쪽 for 절의 반복 가능 표현식을 제외한 어디든 await 표현식이나 다른 비동기 컴프리헨션을 포함하면, 이를 *비동기 컴프리헨션(asynchronous comprehension)*이라고 불러요. 비동기 컴프리헨션은 자신이 나타나는 코루틴 함수의 실행을 일시 중단할 수 있습니다. PEP 530도 참조하세요.
Added in version 3.6: 비동기 컴프리헨션이 도입되었습니다.
Changed in version 3.8: yield와 yield from이 암시적 중첩 스코프에서 금지되었습니다.
Changed in version 3.11: 비동기 함수의 컴프리헨션 안에서 비동기 컴프리헨션을 이제 허용합니다. 바깥 컴프리헨션은 암시적으로 비동기가 됩니다.
6.2.6. 리스트 표시 (List displays)
리스트 표시는 대괄호로 둘러싼, 비어 있을 수 있는 표현식들의 (가능한) 빈 시퀀스예요:
list_display: "[" [flexible_expression_list | comprehension] "]"
리스트 표시는 새 리스트 객체를 산출하며, 내용은 표현식 목록이나 컴프리헨션으로 지정됩니다. 쉼표로 구분된 표현식 목록이 주어지면, 그 요소들은 왼쪽에서 오른쪽으로 평가되어 그 순서대로 리스트 객체에 들어갑니다. 컴프리헨션이 주어지면, 컴프리헨션 결과로 나온 요소들로 리스트가 구성됩니다.
6.2.7. 집합 표시 (Set displays)
집합 표시는 중괄호로 나타내며, 키와 값을 구분하는 콜론이 없다는 점에서 딕셔너리 표시와 구분됩니다:
set_display: "{" (flexible_expression_list | comprehension) "}"
집합 표시는 새 변경 가능한 집합 객체를 산출하며, 내용은 표현식 시퀀스나 컴프리헨션으로 지정됩니다. 쉼표로 구분된 표현식 목록이 주어지면 요소들은 왼쪽에서 오른쪽으로 평가되어 집합 객체에 추가됩니다. 컴프리헨션이 주어지면 컴프리헨션 결과 요소들로 집합이 구성됩니다.
{}로는 빈 집합을 만들 수 없어요. 이 리터럴은 빈 딕셔너리를 만듭니다.
6.2.8. 딕셔너리 표시 (Dictionary displays)
딕셔너리 표시는 중괄호로 둘러싼, 비어 있을 수 있는 일련의 dict 항목(키/값 쌍)이에요:
dict_display: "{" [dict_item_list | dict_comprehension] "}"
dict_item_list: dict_item ("," dict_item)* [","]
dict_item: expression ":" expression | "**" or_expr
dict_comprehension: expression ":" expression comp_for
딕셔너리 표시는 새 딕셔너리 객체를 산출해요.
쉼표로 구분된 dict 항목 시퀀스가 주어지면, 그 항목들은 왼쪽에서 오른쪽으로 평가되어 딕셔너리의 항목을 정의합니다. 각 키 객체는 해당 값을 저장할 딕셔너리 키로 사용됩니다. 즉 dict 항목 목록에서 같은 키를 여러 번 지정할 수 있고, 최종 딕셔너리에서 그 키의 값은 마지막에 주어진 값이 됩니다.
이중 별표 **는 *딕셔너리 언패킹(dictionary unpacking)*을 나타내요. 그 피연산자는 매핑(mapping)이어야 합니다. 각 매핑 항목은 새 딕셔너리에 추가됩니다. 나중의 값은 더 이른 dict 항목과 더 이른 딕셔너리 언패킹으로 이미 설정된 값을 대체합니다.
Added in version 3.5: 원래 PEP 448이 제안한, 딕셔너리 표시로의 언패킹.
딕셔너리 컴프리헨션은 리스트·집합 컴프리헨션과 달리 콜론으로 구분된 두 표현식 뒤에 일반적인 "for"와 "if" 절이 옵니다. 컴프리헨션이 실행될 때, 결과 키와 값 요소는 산출된 순서대로 새 딕셔너리에 삽입됩니다.
키 값 타입에 대한 제한은 앞의 The standard type hierarchy 섹션에 나열되어 있어요. (요약하면, 키 타입은 해시 가능해야 하며, 이는 모든 변경 가능한 객체를 배제합니다.) 중복 키 사이의 충돌은 감지되지 않아요. 주어진 키 값에 저장된 마지막 값(표시에서 텍스트상 가장 오른쪽)이 우선합니다.
Changed in version 3.8: Python 3.8 이전에는 딕셔너리 컴프리헨션에서 키와 값의 평가 순서가 잘 정의되어 있지 않았어요. CPython에서는 값이 키보다 먼저 평가되었습니다. 3.8부터는 PEP 572가 제안한 대로 키가 값보다 먼저 평가됩니다.
6.2.9. 제너레이터 표현식 (Generator expressions)
제너레이터 표현식의 구문은 리스트 컴프리헨션과 동일하지만, 대괄호가 아니라 괄호로 둘러싸여 있어요. 예를 들어:
>>> iterator = (x ** 2 for x in range(10))
>>> iterator
<generator object <genexpr> at ...>
런타임에서 제너레이터 표현식은 대응하는 리스트 컴프리헨션과 같은 값을 산출하는 제너레이터 반복자로 평가됩니다:
>>> 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 섹션을 참조하세요. 예를 들어:
# The parentheses after `sum` are part of the call syntax:
>>> sum(x ** 2 for x in range(10))
285
# The generator needs its own parentheses if it's not the only argument:
>>> 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
다른 모든 표현식은 일반 제너레이터와 같은 방식으로 지연 평가됩니다(즉, 반복자가 값을 산출하도록 요청받을 때):
>>> 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
제너레이터 표현식 자체의 기대 동작을 방해하지 않기 위해, yield와 yield from 표현식은 암시적 중첩 스코프 내부에서 금지됩니다.
제너레이터 표현식이 async for 절이나 await 표현식을 포함하면 *비동기 제너레이터 표현식(asynchronous generator expression)*이라고 불러요. 비동기 제너레이터 표현식은 새 비동기 제너레이터 객체를 반환하며, 이 객체는 비동기 반복자입니다(asynchronous iterators 참조).
제너레이터 표현식의 형식 문법은 다음과 같아요:
generator_expression: "(" expression comp_for ")"
Added in version 3.6: 비동기 제너레이터 표현식이 도입되었습니다.
Changed in version 3.7: Python 3.7 이전에는 비동기 제너레이터 표현식이 async def 코루틴에서만 나타날 수 있었어요. 3.7부터는 어떤 함수든 비동기 제너레이터 표현식을 사용할 수 있습니다.
Changed in version 3.8: yield와 yield from이 암시적 중첩 스코프에서 금지되었습니다.
6.2.10. yield 표현식 (Yield expressions)
yield_atom: "(" yield_expression ")"
yield_from: "yield" "from" expression
yield_expression: "yield" yield_list | yield_from
yield 표현식은 제너레이터 함수나 비동기 제너레이터 함수를 정의할 때 사용되며, 따라서 함수 정의의 본문에서만 사용할 수 있어요. 함수 본문에서 yield 표현식을 사용하면 그 함수는 제너레이터 함수가 되고, async def 함수 본문에서 사용하면 그 코루틴 함수는 비동기 제너레이터 함수가 됩니다. 예를 들어:
def gen(): # defines a generator function
yield 123
async def agen(): # defines an asynchronous generator function
yield 123
포함 스코프에 대한 부작용 때문에, yield 표현식은 컴프리헨션과 제너레이터 표현식을 구현하는 데 사용되는 암시적 정의 스코프의 일부로 허용되지 않습니다.
Changed in version 3.8: 컴프리헨션과 제너레이터 표현식을 구현하는 데 사용되는 암시적 중첩 스코프에서 yield 표현식이 금지되었습니다.
제너레이터 함수는 아래에서 설명하고, 비동기 제너레이터 함수는 Asynchronous generator functions 섹션에서 별도로 설명합니다.
제너레이터 함수가 호출되면 제너레이터(generator)라고 알려진 반복자를 반환해요. 그 제너레이터가 제너레이터 함수의 실행을 제어합니다. 실행은 제너레이터의 메서드 중 하나가 호출될 때 시작됩니다. 그 시점에 실행은 첫 번째 yield 표현식으로 진행되어 다시 일시 중단되고, yield_list의 값을 제너레이터의 호출자에게 반환합니다. yield_list가 생략되면 None을 반환합니다. 일시 중단(suspended)은 모든 로컬 상태 — 로컬 변수의 현재 바인딩, 명령 포인터, 내부 평가 스택, 예외 처리 상태 — 가 유지된다는 뜻이에요.
제너레이터의 메서드 중 하나를 호출해 실행을 재개하면, 함수는 yield 표현식이 또 하나의 외부 호출인 것처럼 정확히 진행할 수 있어요. 재개 후 yield 표현식의 값은 실행을 재개한 메서드에 따라 달라집니다. __next__()를 사용하면(보통 for 또는 next() 내장 함수를 통해) 결과는 None이에요. 그렇지 않고 send()를 사용하면 그 메서드에 전달된 값이 결과가 됩니다.
이 모든 것은 제너레이터 함수를 코루틴과 상당히 유사하게 만듭니다. 여러 번 yield하고, 진입점이 둘 이상이며, 실행을 일시 중단할 수 있어요. 유일한 차이는 제너레이터 함수가 yield 후 실행을 어디서 계속할지를 제어할 수 없다는 점입니다. 제어는 항상 제너레이터의 호출자로 이전됩니다.
yield 표현식은 try 구성의 어디든 허용돼요. 제너레이터가 (참조 횟수 0에 도달하거나 가비지 컬렉션으로) 최종화(finalized)되기 전에 재개되지 않으면, 제너레이터 반복자의 close() 메서드가 호출되어 보류 중인 finally 절이 실행될 수 있습니다.
yield from <expr>을 사용하면 주어진 표현식은 반복 가능해야 해요. 그 반복 가능 객체를 반복하며 만들어지는 값은 현재 제너레이터 메서드의 호출자에게 직접 전달됩니다. send()로 전달된 값과 throw()로 전달된 예외는, 그 기반 반복자에 적절한 메서드가 있으면 기반 반복자에 전달됩니다. 그렇지 않으면 send()는 AttributeError 또는 TypeError를 발생시키고, throw()는 전달된 예외를 즉시 그냥 발생시킵니다.
기반 반복자가 완료되면, 발생한 StopIteration 인스턴스의 value 속성이 yield 표현식의 값이 됩니다. 이는 StopIteration을 발생시킬 때 명시적으로 설정하거나, 하위 반복자가 제너레이터일 때(하위 제너레이터에서 값을 반환함으로써) 자동으로 설정할 수 있어요.
Changed in version 3.3: yield from <expr>이 추가되어 제어 흐름을 하위 반복자에 위임할 수 있게 되었습니다.
yield 표현식이 할당 문의 오른쪽에 있는 유일한 표현식이면 괄호를 생략할 수 있어요.
See also
PEP 255 - Simple Generators
Python에 제너레이터와 yield 문을 추가하는 제안.
PEP 342 - Coroutines via Enhanced Generators
제너레이터의 API와 구문을 강화해 간단한 코루틴으로 사용 가능하게 만드는 제안.
PEP 380 - Syntax for Delegating to a Subgenerator
하위 제너레이터로의 위임을 쉽게 만드는 yield_from 구문을 도입하는 제안.
PEP 525 - Asynchronous Generators
PEP 492를 확장해 코루틴 함수에 제너레이터 능력을 추가한 제안.
6.2.10.1. 제너레이터 반복자 메서드 (Generator-iterator methods)
이 하위 섹션은 제너레이터 반복자의 메서드를 설명해요. 이들은 제너레이터 함수의 실행을 제어하는 데 사용됩니다.
제너레이터가 이미 실행 중일 때 아래의 제너레이터 메서드 중 하나를 호출하면 ValueError 예외가 발생한다는 점에 주의하세요.
generator.next()
제너레이터 함수의 실행을 시작하거나 마지막으로 실행된 yield 표현식에서 재개합니다. 제너레이터 함수가 __next__() 메서드로 재개되면 현재 yield 표현식은 항상 None으로 평가됩니다. 그런 다음 실행은 다음 yield 표현식으로 계속되어 제너레이터가 다시 일시 중단되고, yield_list의 값이 __next__()의 호출자에게 반환됩니다. 제너레이터가 다른 값을 yield하지 않고 종료되면 StopIteration 예외가 발생합니다.
이 메서드는 보통 for 루프나 내장 next() 함수에 의해 암시적으로 호출됩니다.
generator.send(value)
실행을 재개하고 제너레이터 함수에 값을 "보냅니다". value 인수는 현재 yield 표현식의 결과가 됩니다. send() 메서드는 제너레이터가 산출하는 다음 값을 반환하거나, 제너레이터가 다른 값을 yield하지 않고 종료하면 StopIteration을 발생시킵니다. 제너레이터를 시작하기 위해 send()를 호출할 때는 값이 None이어야 합니다. 그 값을 받을 yield 표현식이 없기 때문이에요.
generator.throw(value)
generator.throw(type[, value[, traceback]])
제너레이터가 일시 중단된 지점에서 예외를 발생시키고, 제너레이터 함수가 산출하는 다음 값을 반환합니다. 제너레이터가 다른 값을 yield하지 않고 종료하면 StopIteration 예외가 발생합니다. 제너레이터 함수가 전달된 예외를 잡지 않거나 다른 예외를 발생시키면 그 예외는 호출자에게 전파됩니다.
일반적으로 사용 시에는 raise 키워드를 쓰는 것과 유사하게 단일 예외 인스턴스로 호출됩니다.
하지만 이전 버전의 Python 규약을 따라 호환성을 위해 두 번째 시그니처도 지원됩니다. type 인수는 예외 클래스여야 하고 value는 예외 인스턴스여야 해요. value가 제공되지 않으면 type 생성자를 호출해 인스턴스를 얻습니다. traceback이 제공되면 예외에 설정되고, 그렇지 않으면 value에 저장된 기존 __traceback__ 속성이 지워질 수 있습니다.
Changed in version 3.12: 두 번째 시그니처 (type[, value[, traceback]])는 더 이상 사용되지 않으며( deprecation) 향후 Python 버전에서 제거될 수 있습니다.
generator.close()
제너레이터 함수가 일시 중단된 지점에서 GeneratorExit 예외를 발생시킵니다(throw(GeneratorExit) 호출과 동등). 예외는 제너레이터가 일시 중단된 yield 표현식에 의해 발생합니다. 제너레이터 함수가 예외를 잡고 값을 반환하면 이 값이 close()에서 반환됩니다. 제너레이터 함수가 이미 닫혀 있거나 GeneratorExit를 (예외를 잡지 않음으로써) 발생시키면 close()는 None을 반환합니다. 제너레이터가 값을 yield하면 RuntimeError가 발생합니다. 제너레이터가 다른 예외를 발생시키면 호출자에게 전파됩니다. 제너레이터가 예외 또는 정상 종료로 이미 빠져나갔으면 close()는 None을 반환하고 다른 효과가 없습니다.
Changed in version 3.13: 제너레이터가 닫힐 때 값을 반환하면 그 값이 close()에 의해 반환됩니다.
6.2.10.2. 예 (Examples)
제너레이터와 제너레이터 함수의 동작을 보여주는 간단한 예시를 들어볼게요:
>>> 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: Syntax for Delegating to a Subgenerator를 참조하세요.
6.2.10.3. 비동기 제너레이터 함수 (Asynchronous generator functions)
async def로 정의된 함수나 메서드에 yield 표현식이 있으면 그 함수를 비동기 제너레이터 함수로 더 정의합니다.
비동기 제너레이터 함수가 호출되면 비동기 제너레이터 객체라고 알려진 비동기 반복자를 반환해요. 그 객체가 제너레이터 함수의 실행을 제어합니다. 비동기 제너레이터 객체는 일반적으로 코루틴 함수의 async for 문에서 사용되며, 이는 제너레이터 객체가 for 문에서 사용되는 방식과 유사합니다.
비동기 제너레이터의 메서드 중 하나를 호출하면 어웨이터블(awaitable) 객체가 반환되고, 이 객체가 await될 때 실행이 시작됩니다. 그 시점에 실행은 첫 번째 yield 표현식으로 진행되어 다시 일시 중단되고, yield_list의 값을 await 중인 코루틴에게 반환합니다. 제너레이터와 마찬가지로 일시 중단은 로컬 변수의 현재 바인딩, 명령 포인터, 내부 평가 스택, 예외 처리 상태를 포함한 모든 로컬 상태가 유지된다는 뜻입니다. 비동기 제너레이터의 메서드가 반환하는 다음 객체를 await하여 실행을 재개하면, 함수는 yield 표현식이 또 하나의 외부 호출인 것처럼 정확히 진행할 수 있어요. 재개 후 yield 표현식의 값은 실행을 재개한 메서드에 따라 달라집니다. __anext__()를 사용하면 결과는 None이에요. 그렇지 않고 asend()를 사용하면 그 메서드에 전달된 값이 결과가 됩니다.
비동기 제너레이터가 break, 호출자 태스크 취소 또는 다른 예외로 일찍 종료되면, 제너레이터의 async 정리 코드가 실행되어 예기치 않은 컨텍스트에서 예외를 발생시키거나 컨텍스트 변수에 접근할 수 있어요 — 의존하는 태스크의 수명 이후나, 비동기 제너레이터 가비지 컬렉션 훅이 호출되는 이벤트 루프 종료 중일 수 있습니다. 이를 막으려면 호출자는 aclose() 메서드를 호출해 비동기 제너레이터를 명시적으로 닫아 최종화하고 궁극적으로 이벤트 루프에서 분리해야 합니다.
비동기 제너레이터 함수에서는 yield 표현식이 try 구성의 어디든 허용됩니다. 하지만 비동기 제너레이터가 (참조 횟수 0에 도달하거나 가비지 컬렉션으로) 최종화되기 전에 재개되지 않으면, try 구성 안의 yield 표현식은 보류 중인 finally 절 실행 실패로 이어질 수 있어요. 이 경우 비동기 제너레이터를 실행하는 이벤트 루프나 스케줄러가 비동기 제너레이터 반복자의 aclose() 메서드를 호출하고 결과 코루틴 객체를 실행해, 보류 중인 finally 절이 실행되도록 하는 것이 책임입니다.
이벤트 루프 종료 시 최종화를 처리하기 위해, 이벤트 루프는 비동기 제너레이터 반복자를 받아 aclose()를 호출하고 코루틴을 실행하는 finalizer 함수를 정의해야 해요. 이 finalizer는 sys.set_asyncgen_hooks()로 등록할 수 있습니다. 비동기 제너레이터 반복자를 처음 반복하면 등록된 finalizer를 저장해 최종화 시 호출하게 됩니다. finalizer 메서드의 참조 예는 Lib/asyncio/base_events.py의 asyncio.Loop.shutdown_asyncgens 구현을 참조하세요.
yield from <expr> 표현식은 비동기 제너레이터 함수에서 사용하면 구문 오류입니다.
6.2.10.4. 비동기 제너레이터 반복자 메서드 (Asynchronous generator-iterator methods)
이 하위 섹션은 제너레이터 함수의 실행을 제어하는 데 사용되는 비동기 제너레이터 반복자의 메서드를 설명합니다.
async agen.anext()
실행 시 비동기 제너레이터 실행을 시작하거나 마지막으로 실행된 yield 표현식에서 재개하는 어웨이터블을 반환해요. 비동기 제너레이터 함수가 __anext__() 메서드로 재개되면 반환된 어웨이터블에서 현재 yield 표현식은 항상 None으로 평가되고, 실행 시 다음 yield 표현식으로 계속됩니다. yield 표현식의 yield_list의 값은 완료 코루틴이 발생시키는 StopIteration 예외의 값입니다. 비동기 제너레이터가 다른 값을 yield하지 않고 종료되면 어웨이터블은 대신 StopAsyncIteration 예외를 발생시켜 비동기 반복이 완료되었음을 알립니다.
이 메서드는 보통 async for 루프에 의해 암시적으로 호출됩니다.
async agen.asend(value)
실행 시 비동기 제너레이터의 실행을 재개하는 어웨이터블을 반환해요. 제너레이터에 대한 send() 메서드와 마찬가지로 비동기 제너레이터 함수에 값을 "보내며", value 인수는 현재 yield 표현식의 결과가 됩니다. asend() 메서드가 반환하는 어웨이터블은 제너레이터가 산출하는 다음 값을 발생된 StopIteration의 값으로 반환하거나, 비동기 제너레이터가 다른 값을 yield하지 않고 종료하면 StopAsyncIteration을 발생시킵니다. 비동기 제너레이터를 시작하기 위해 asend()를 호출할 때는 값이 None이어야 합니다. 그 값을 받을 yield 표현식이 없기 때문이에요.
async agen.athrow(value)
async agen.athrow(type[, value[, traceback]])
비동기 제너레이터가 일시 중단된 지점에서 type 타입의 예외를 발생시키고, 제너레이터 함수가 산출하는 다음 값을 발생된 StopIteration 예외의 값으로 반환하는 어웨이터블을 반환해요. 비동기 제너레이터가 다른 값을 yield하지 않고 종료되면 어웨이터블은 StopAsyncIteration 예외를 발생시킵니다. 제너레이터 함수가 전달된 예외를 잡지 않거나 다른 예외를 발생시키면, 어웨이터블이 실행될 때 그 예외는 어웨이터블의 호출자에게 전파됩니다.
Changed in version 3.12: 두 번째 시그니처 (type[, value[, traceback]])는 더 이상 사용되지 않으며 향후 Python 버전에서 제거될 수 있습니다.
async agen.aclose()
실행 시 비동기 제너레이터 함수가 일시 중단된 지점에 GeneratorExit를 던지는 어웨이터블을 반환해요. 비동기 제너레이터 함수가 그 후 정상적으로 종료되거나, 이미 닫혀 있거나, GeneratorExit를 (예외를 잡지 않음으로써) 발생시키면 반환된 어웨이터블은 StopIteration 예외를 발생시킵니다. 비동기 제너레이터에 대한 이후 호출이 반환하는 추가 어웨이터블은 StopAsyncIteration 예외를 발생시킵니다. 비동기 제너레이터가 값을 yield하면 어웨이터블은 RuntimeError를 발생시킵니다. 비동기 제너레이터가 다른 예외를 발생시키면 어웨이터블의 호출자에게 전파됩니다. 비동기 제너레이터가 예외 또는 정상 종료로 이미 빠져나갔으면 aclose()에 대한 이후 호출은 아무것도 하지 않는 어웨이터블을 반환합니다.
6.3. 일차 표현식 (Primaries)
일차 표현식(primary)은 언어에서 가장 강하게 결합된 연산을 나타냅니다. 그 구문은:
primary: atom | attributeref | subscription | call
6.3.1. 속성 참조 (Attribute references)
속성 참조는 일차 표현식 뒤에 마침표와 이름이 오는 형태예요:
attributeref: primary "." identifier
일차 표현식은 속성 참조를 지원하는 타입의 객체로 평가되어야 해요. 대부분의 객체가 이를 지원합니다. 그런 다음 이 객체에 이름(식별자)인 속성을 만들어 달라고 요청합니다. 만들어지는 타입과 값은 객체가 결정합니다. 같은 속성 참조를 여러 번 평가하면 서로 다른 객체가 나올 수 있어요.
이 생성(production)은 __getattribute__() 메서드나 __getattr__() 메서드를 오버라이드하여 사용자화할 수 있어요. __getattribute__() 메서드가 먼저 호출되어 값을 반환하거나, 속성이 사용 가능하지 않으면 AttributeError를 발생시킵니다.
AttributeError가 발생하고 객체에 __getattr__() 메서드가 있으면 그 메서드가 대체(fallback)로 호출됩니다.
6.3.2. 첨자와 슬라이싱 (Subscriptions and slicings)
첨자(subscription) 구문은 보통 컨테이너에서 요소를 선택하는 데 사용돼요 — 예를 들어 dict에서 값을 가져올 때:
>>> digits_by_name = {'one': 1, 'two': 2}
>>> digits_by_name['two'] # Subscripting a dictionary using the key 'two'
2
첨자 구문에서 첨자(subscript)를 당하는 객체(일차 표현식) 뒤에 대괄호 안의 *첨자(subscript)*가 옵니다. 가장 단순한 경우 첨자는 단일 표현식이에요.
첨자를 당하는 객체의 타입에 따라, 첨자는 키(key, 매핑의 경우), 인덱스(index, 시퀀스의 경우) 또는 *타입 인수(type argument, 제네릭 타입의 경우)*라고 불리기도 합니다. 문법적으로는 모두 동등합니다:
>>> colors = ['red', 'blue', 'green', 'black']
>>> colors[3] # Subscripting a list using the index 3
'black'
>>> list[str] # Parameterizing the list type using the type argument str
list[str]
런타임에서 인터프리터는 일차 표현식과 첨자를 평가하고, 첨자를 인수로 일차 표현식의 __getitem__() 또는 __class_getitem__() 특수 메서드를 호출합니다. 이 메서드 중 어느 것이 호출되는지에 대한 자세한 내용은 class_getitem versus __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__() 문서를 참조하세요.
첨자는 할당이나 삭제 문의 대상으로도 사용될 수 있어요. 이 경우 인터프리터는 __getitem__() 대신 첨자 객체의 __setitem__() 또는 __delitem__() 특수 메서드를 각각 호출합니다.
>>> colors = ['red', 'blue', 'green', 'black']
>>> colors[3] = 'white' # Setting item at index
>>> colors
['red', 'blue', 'green', 'white']
>>> del colors[3] # Deleting item at index 3
>>> colors
['red', 'blue', 'green']
다음 섹션들에서 설명하는 첨자의 모든 고급 형태는 할당과 삭제에도 사용할 수 있어요.
6.3.2.1. 슬라이싱 (Slicings)
더 고급 형태의 첨자인 *슬라이싱(slicing)*은 보통 시퀀스의 일부를 추출하는 데 사용됩니다. 이 형태에서 첨자는 슬라이스(slice)예요: 콜론으로 구분된 최대 세 개의 표현식. 어떤 표현식이든 생략할 수 있지만, 슬라이스는 최소 하나의 콜론을 포함해야 합니다:
>>> 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']
슬라이스가 평가되면 인터프리터는 콜론 사이의 표현식 결과를 각각 start, stop, step 속성으로 갖는 slice 객체를 만듭니다. 누락된 표현식은 None으로 평가됩니다. 그런 다음 이 slice 객체는 위와 같이 __getitem__() 또는 __class_getitem__() 특수 메서드에 전달됩니다.
# continuing with the SubscriptionDemo instance defined above:
>>> demo[2:3]
subscripted with: slice(2, 3, None)
>>> demo[::'spam']
subscripted with: slice(None, None, 'spam')
6.3.2.2. 쉼표로 구분된 첨자 (Comma-separated subscripts)
첨자는 두 개 이상의 쉼표로 구분된 표현식이나 슬라이스로도 주어질 수 있어요:
# continuing with the SubscriptionDemo instance defined above:
>>> demo[1, 2, 3]
subscripted with: (1, 2, 3)
>>> demo[1:2, 3]
subscripted with: (slice(1, 2, None), 3)
이 형태는 수치 라이브러리에서 다차원 데이터를 슬라이싱할 때 흔히 사용됩니다. 이 경우 인터프리터는 표현식이나 슬라이스 결과들의 tuple을 만들어 위와 같이 __getitem__() 또는 __class_getitem__() 특수 메서드에 전달합니다.
첨자는 단일 표현식이나 슬라이스 뒤에 쉼표가 오는 형태로 주어져 1-요소 튜플을 지정할 수도 있어요:
>>> demo['spam',]
subscripted with: ('spam',)
6.3.2.3. "별표" 첨자 ("Starred" subscriptions)
Added in version 3.11: tuple_slices의 표현식은 별표(starred)일 수 있습니다. PEP 646 참조.
첨자는 별표 표현식(starred expression)을 포함할 수 있어요. 이 경우 인터프리터는 결과를 튜플로 풀고 이 튜플을 __getitem__() 또는 __class_getitem__()에 전달합니다:
# continuing with the SubscriptionDemo instance defined above:
>>> 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. 형식 첨자 문법 (Formal subscription grammar)
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)+ [',']
| 연산자가 순서가 있는 선택(ordered choice)을 나타낸다는 점을 기억하세요. 특히 subscript에서 두 대안이 모두 일치하면 첫 번째(single_subscript)가 우선합니다.
6.3.3. 호출 (Calls)
호출(call)은 호출 가능 객체(예: 함수)를, 비어 있을 수 있는 일련의 인수로 호출합니다:
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
위치 인수와 키워드 인수 뒤에는 선택적인 후행 쉼표가 있을 수 있지만 의미에는 영향을 주지 않습니다.
일차 표현식은 호출 가능 객체로 평가되어야 해요(사용자 정의 함수, 내장 함수, 내장 객체의 메서드, 클래스 객체, 클래스 인스턴스의 메서드, 그리고 __call__() 메서드를 가진 모든 객체는 호출 가능합니다). 모든 인수 표현식은 호출이 시도되기 전에 평가됩니다. 형식 매개변수 목록의 구문은 Function definitions 섹션을 참조하세요.
키워드 인수가 있으면 다음과 같이 먼저 위치 인수로 변환됩니다. 먼저 형식 매개변수에 대한 비어 있는 슬롯 목록이 만들어집니다. N개의 위치 인수가 있으면 처음 N개의 슬롯에 배치됩니다. 다음으로 각 키워드 인수에 대해 식별자로 해당 슬롯을 결정합니다(식별자가 첫 번째 형식 매개변수 이름과 같으면 첫 번째 슬롯이 사용되는 식입니다). 슬롯이 이미 채워져 있으면 TypeError 예외가 발생합니다. 그렇지 않으면 그 슬롯을 채워 인수가 배치됩니다(표현식이 None이어도 슬롯을 채웁니다). 모든 인수가 처리되면 여전히 비어 있는 슬롯은 함수 정의의 해당 기본값으로 채워집니다. (기본값은 함수가 정의될 때 한 번 계산됩니다. 따라서 목록이나 딕셔너리 같은 변경 가능한 객체를 기본값으로 사용하면 해당 슬롯에 대한 인수 값을 지정하지 않는 모든 호출이 그 객체를 공유하게 됩니다. 이는 보통 피해야 합니다.) 기본값이 지정되지 않은 채워지지 않은 슬롯이 있으면 TypeError 예외가 발생합니다. 그렇지 않으면 채워진 슬롯 목록이 호출의 인수 목록으로 사용됩니다.
CPython implementation detail: 구현은 문서화 목적으로 '이름이 지정되더라도' 위치 매개변수에 이름이 없는 내장 함수를 제공할 수 있으며, 따라서 키워드로 제공할 수 없습니다. CPython에서는 PyArg_ParseTuple()로 인수를 구문 분석하는 C로 구현된 함수가 그 경우에 해당합니다.
형식 매개변수 슬롯보다 위치 인수가 더 많으면 TypeError 예외가 발생합니다. 단, *identifier 구문을 사용하는 형식 매개변수가 있으면 예외 대신 그 형식 매개변수가 초과 위치 인수를 포함하는 튜플(초과 위치 인수가 없으면 빈 튜플)을 받습니다.
키워드 인수가 형식 매개변수 이름에 대응하지 않으면 TypeError 예외가 발생합니다. 단, **identifier 구문을 사용하는 형식 매개변수가 있으면 예외 대신 그 형식 매개변수가 초과 키워드 인수를 포함하는 딕셔너리(키워드를 키로, 인수 값을 값으로) 또는 초과 키워드 인수가 없으면 (새) 빈 딕셔너리를 받습니다.
함수 호출에 *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은 매핑으로 평가되어야 하며, 그 내용은 추가 키워드 인수로 취급됩니다. 키에 일치하는 매개변수가 이미 값(명시적 키워드 인수나 다른 언패킹으로)을 받은 경우 TypeError 예외가 발생합니다.
**expression이 사용되면 이 매핑의 각 키는 문자열이어야 합니다. 매핑의 각 값은 키와 이름이 같은 키워드 할당 자격이 있는 첫 번째 형식 매개변수에 할당됩니다. 키는 Python 식별자일 필요가 없어요(예: "max-temp °F"는 허용되지만, 선언될 수 있는 어떤 형식 매개변수와도 일치하지 않습니다). 형식 매개변수와 일치하는 것이 없으면 키-값 쌍은 ** 매개변수가 있으면 그것이 수집하고, 없으면 TypeError 예외가 발생합니다.
*identifier 또는 **identifier 구문을 사용하는 형식 매개변수는 위치 인수 슬롯이나 키워드 인수 이름으로 사용될 수 없습니다.
Changed in version 3.5: 함수 호출이 임의 개수의 * 및 ** 언패킹을 허용하고, 위치 인수가 반복 가능 언패킹(*) 뒤에 올 수 있으며, 키워드 인수가 딕셔너리 언패킹(**) 뒤에 올 수 있습니다. 원래 PEP 448이 제안했습니다.
호출은 예외를 발생시키지 않으면 항상 어떤 값(어쩌면 None)을 반환합니다. 이 값이 어떻게 계산되는지는 호출 가능 객체의 타입에 따라 다릅니다.
만약 그것이 —
사용자 정의 함수:
함수의 코드 블록이 인수 목록을 전달받아 실행됩니다. 코드 블록이 가장 먼저 하는 일은 형식 매개변수를 인수에 바인딩하는 것입니다. 이는 Function definitions 섹션에 설명되어 있습니다. 코드 블록이 return 문을 실행하면 이것이 함수 호출의 반환 값을 지정합니다. 함수 코드 블록을 return 문을 실행하지 않고 끝까지 실행하면 반환 값은 None입니다.
내장 함수 또는 메서드:
결과는 인터프리터에 달려 있습니다. 내장 함수·메서드의 설명은 Built-in Functions를 참조하세요.
클래스 객체:
그 클래스의 새 인스턴스가 반환됩니다.
클래스 인스턴스 메서드:
해당 사용자 정의 함수가 호출되는데, 호출의 인수 목록보다 하나 긴 인수 목록으로 호출됩니다. 인스턴스가 첫 번째 인수가 됩니다.
클래스 인스턴스:
클래스는 __call__() 메서드를 정의해야 합니다. 그러면 그 메서드가 호출된 것과 같은 효과가 있습니다.
6.4. await 표현식 (Await expression)
어웨이터블 객체에서 코루틴의 실행을 일시 중단합니다. 코루틴 함수 내부에서만 사용할 수 있어요.
await_expr: "await" primary
Added in version 3.5.
6.5. 거듭제곱 연산자 (The power operator)
거듭제곱 연산자는 왼쪽의 단항 연산자보다 더 강하게 결합하고, 오른쪽의 단항 연산자보다는 더 약하게 결합합니다. 구문은:
power: (await_expr | primary) ["**" u_expr]
따라서 괄호 없는 거듭제곱과 단항 연산자 시퀀스에서 연산자는 오른쪽에서 왼쪽으로 평가됩니다(이것이 피연산자의 평가 순서를 제한하지는 않습니다): -1**2는 -1이 됩니다.
거듭제곱 연산자는 두 인수로 호출된 내장 pow() 함수와 같은 의미를 가져요. 왼쪽 인수를 오른쪽 인수의 거듭제곱으로 올립니다. 숫자 인수는 먼저 공통 타입으로 변환되고, 결과는 그 타입입니다.
int 피연산자의 경우, 두 번째 인수가 음수가 아니면 결과는 피연산자와 같은 타입입니다. 두 번째 인수가 음수이면 모든 인수가 float로 변환되고 float 결과가 전달됩니다. 예를 들어 10**2는 100을 반환하지만 10**-2는 0.01을 반환합니다.
0.0을 음의 거듭제곱으로 올리면 ZeroDivisionError가 발생합니다. 음수를 분수 거듭제곱으로 올리면 complex 숫자가 됩니다. (이전 버전에서는 ValueError를 발생시켰습니다.)
이 연산은 특수 __pow__() 및 __rpow__() 메서드로 사용자화할 수 있어요.
6.6. 단항 산술 및 비트 연산 (Unary arithmetic and bitwise operations)
모든 단항 산술 및 비트 연산은 같은 우선순위를 가집니다:
u_expr: power | "-" u_expr | "+" u_expr | "~" u_expr
단항 -(빼기) 연산자는 숫자 인수의 부정을 산출하며, 이 연산은 __neg__() 특수 메서드로 오버라이드할 수 있어요.
단항 +(더하기) 연산자는 숫자 인수를 그대로 산출하며, 이 연산은 __pos__() 특수 메서드로 오버라이드할 수 있습니다.
단항 ~(반전) 연산자는 정수 인수의 비트 반전을 산출합니다. x의 비트 반전은 -(x+1)로 정의됩니다. 정수 또는 __invert__() 특수 메서드를 오버라이드하는 사용자 정의 객체에만 적용됩니다.
세 경우 모두 인수가 적절한 타입이 아니면 TypeError 예외가 발생합니다.
6.7. 이항 산술 연산 (Binary arithmetic operations)
이항 산술 연산은 전통적인 우선순위 수준을 가집니다. 이 연산 중 일부는 특정 비-숫자 타입에도 적용된다는 점에 주의하세요. 거듭제곱 연산자를 제외하면 두 수준만 있는데, 하나는 곱셈 연산자, 하나는 덧셈 연산자입니다:
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__() 메서드로 사용자화할 수 있어요.
Changed in version 3.14: 피연산자 중 하나만 복소수면 다른 피연산자는 부동소수점 수로 변환됩니다.
@(at) 연산자는 행렬 곱셈에 사용하기 위한 것입니다. 내장 Python 타입 중 이 연산자를 구현하는 것은 없습니다.
이 연산은 특수 __matmul__() 및 __rmatmul__() 메서드로 사용자화할 수 있어요.
Added in version 3.5.
/(나눗셈)와 //(바닥 나눗셈) 연산자는 인수의 몫을 산출합니다. 숫자 인수는 먼저 공통 타입으로 변환됩니다. 정수 나눗셈은 float를 산출하고, 정수 바닥 나눗셈은 정수를 산출합니다. 후자는 결과에 'floor' 함수가 적용된 수학적 나눗셈의 결과입니다. 0으로 나누면 ZeroDivisionError 예외가 발생합니다.
나눗셈 연산은 특수 __truediv__() 및 __rtruediv__() 메서드로 사용자화할 수 있어요. 바닥 나눗셈 연산은 특수 __floordiv__() 및 __rfloordiv__() 메서드로 사용자화할 수 있습니다.
%(나머지) 연산자는 첫 번째 인수를 두 번째로 나눈 나머지를 산출합니다. 숫자 인수는 먼저 공통 타입으로 변환됩니다. 오른쪽 인수가 0이면 ZeroDivisionError 예외가 발생합니다. 인수는 부동소수점 수일 수 있어요. 예를 들어 3.14%0.7은 0.34와 같습니다(3.14는 4*0.7 + 0.34이므로). 나머지 연산자는 항상 두 번째 피연산자와 같은 부호의 결과(또는 0)를 산출하며, 결과의 절대값은 두 번째 피연산자의 절대값보다 엄밀히 작습니다 [1].
바닥 나눗셈과 나머지 연산자는 다음 항등식으로 연결됩니다: x == (x//y)*y + (x%y). 바닥 나눗셈과 나머지는 내장 함수 divmod()와도 연결됩니다: divmod(x, y) == (x//y, x%y). [2]
숫자에 대해 나머지 연산을 수행하는 것 외에도 % 연산자는 문자열 객체에 의해 오버로드되어 구식 문자열 형식화(문자열 보간이라고도 함)를 수행합니다. 문자열 형식화의 구문은 Python Library Reference의 printf-style String Formatting 섹션에 설명되어 있습니다.
나머지 연산은 특수 __mod__() 및 __rmod__() 메서드로 사용자화할 수 있어요.
바닥 나눗셈 연산자, 나머지 연산자, divmod() 함수는 복소수에 대해 정의되지 않습니다. 대신 적절하다면 abs() 함수를 사용해 부동소수점 수로 변환하세요.
+(덧셈) 연산자는 인수의 합을 산출합니다. 인수는 둘 다 숫자이거나 둘 다 같은 타입의 시퀀스여야 합니다. 전자의 경우 숫자는 공통 실수 타입으로 변환된 후 함께 더해집니다. 후자의 경우 시퀀스가 연결됩니다.
이 연산은 특수 __add__() 및 __radd__() 메서드로 사용자화할 수 있어요.
Changed in version 3.14: 피연산자 중 하나만 복소수면 다른 피연산자는 부동소수점 수로 변환됩니다.
-(뺄셈) 연산자는 인수의 차를 산출합니다. 숫자 인수는 먼저 공통 실수 타입으로 변환됩니다.
이 연산은 특수 __sub__() 및 __rsub__() 메서드로 사용자화할 수 있어요.
Changed in version 3.14: 피연산자 중 하나만 복소수면 다른 피연산자는 부동소수점 수로 변환됩니다.
6.8. 시프트 연산 (Shifting operations)
시프트 연산은 산술 연산보다 낮은 우선순위를 가집니다:
shift_expr: a_expr | shift_expr ("<<" | ">>") a_expr
이 연산자는 인수로 정수를 받습니다. 첫 번째 인수를 두 번째 인수가 주는 비트 수만큼 왼쪽 또는 오른쪽으로 시프트합니다.
왼쪽 시프트 연산은 특수 __lshift__() 및 __rlshift__() 메서드로 사용자화할 수 있어요. 오른쪽 시프트 연산은 특수 __rshift__() 및 __rrshift__() 메서드로 사용자화할 수 있습니다.
n 비트 오른쪽 시프트는 pow(2,n)으로 바닥 나눗셈하는 것으로 정의됩니다. n 비트 왼쪽 시프트는 pow(2,n)으로 곱하는 것으로 정의됩니다.
6.9. 이항 비트 연산 (Binary bitwise operations)
세 비트 연산은 각각 다른 우선순위 수준을 가집니다:
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. 비교 (Comparisons)
C와 달리 Python의 모든 비교 연산은 같은 우선순위를 가지며, 이는 어떤 산술, 시프트 또는 비트 연산보다 낮아요. 또한 C와 달리 a < b < c 같은 표현식은 수학에서 관례적인 해석을 가집니다:
comparison: or_expr (comp_operator or_expr)*
comp_operator: "<" | ">" | "==" | ">=" | "<=" | "!="
| "is" ["not"] | ["not"] "in"
비교는 불리언 값인 True 또는 False를 산출합니다. 사용자 정의 *풍부 비교 메서드(rich comparison methods)*는 비-불리언 값을 반환할 수 있어요. 이 경우 Python은 불리언 컨텍스트에서 그 값에 bool()을 호출합니다.
비교는 임의로 연결(chain)될 수 있어요. 예를 들어 x < y <= z는 x < 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 c가 a와 c 사이의 어떤 종류의 비교를 의미하지는 않는다는 점에 주의하세요. 따라서 예를 들어 x < y > z는 완전히 합법적입니다(아마 예쁘지는 않지만).
6.10.1. 값 비교 (Value comparisons)
<, >, ==, >=, <=, != 연산자는 두 객체의 값을 비교합니다. 객체는 같은 타입일 필요가 없습니다.
Objects, values and types 장은 객체가 (타입과 정체성 외에) 값을 가진다고 말합니다. 객체의 값은 Python에서 상당히 추상적인 개념이에요. 예를 들어 객체의 값에 대한 정규 접근 메서드가 없습니다. 또한 객체의 값이 특정 방식으로(예: 모든 데이터 속성으로 구성) 구성되어야 한다는 요구도 없습니다. 비교 연산자는 객체의 값이 무엇인지에 대한 특정 개념을 구현합니다. 비교 구현을 통해 객체의 값을 간접적으로 정의한다고 생각할 수 있습니다.
모든 타입은 object의 (직간접적) 하위 타입이므로 object로부터 기본 비교 동작을 상속합니다. 타입은 Basic customization에 설명된 __lt__() 같은 풍부 비교 메서드를 구현해 비교 동작을 사용자화할 수 있어요.
동등 비교(==와 !=)의 기본 동작은 객체의 정체성에 기반합니다. 따라서 정체성이 같은 인스턴스의 동등 비교는 같음으로, 정체성이 다른 인스턴스의 동등 비교는 같지 않음으로 이어집니다. 이 기본 동작의 동기는 모든 객체가 반사적(reflexive)이어야 한다는 바람입니다(즉 x is y가 x == y를 함의).
기본 순서 비교(<, >, <=, >=)는 제공되지 않습니다. 시도하면 TypeError가 발생합니다. 이 기본 동작의 동기는 동등성과 같은 불변(invariant)이 없다는 것입니다.
정체성이 다른 인스턴스는 항상 같지 않다는 기본 동등 비교 동작은, 객체 값과 값 기반 동등성의 타당한 정의를 가진 타입이 필요로 하는 것과 대조될 수 있어요. 그런 타입은 비교 동작을 사용자화해야 하며, 실제로 많은 내장 타입이 그렇게 했습니다.
다음 목록은 가장 중요한 내장 타입의 비교 동작을 설명합니다.
내장 수치 타입(Numeric Types — int, float, complex)과 표준 라이브러리 타입 fractions.Fraction 및 decimal.Decimal의 숫자는 타입 내부와 타입 간에 비교될 수 있지만, 복소수는 순서 비교를 지원하지 않는다는 제한이 있습니다. 관련된 타입의 한계 내에서 정밀도 손실 없이 수학적(알고리즘적으로) 정확하게 비교합니다.
not-a-number 값인 float('NaN')과 decimal.Decimal('NaN')은 특별합니다. 숫자와 not-a-number 값의 어떤 순서 비교도 거짓입니다. 직관에 반하는 결과로, not-a-number 값은 자기 자신과 같지 않습니다. 예를 들어 x = float('NaN')이면 3 < x, x < 3, x == x는 모두 거짓이고 x != x는 참입니다. 이 동작은 IEEE 754를 따릅니다.
None과 NotImplemented는 싱글턴(singleton)입니다. PEP 8은 싱글턴에 대한 비교는 항상 is 또는 is not으로 해야 하고, 동등 연산자는 절대 쓰지 말라고 권고합니다.
이진 시퀀스(bytes 또는 bytearray 인스턴스)는 타입 내부와 타입 간에 비교될 수 있습니다. 요소의 숫자 값을 사용해 사전식(lexicographically)으로 비교합니다.
문자열(str 인스턴스)은 문자의 수치 유니코드 코드 포인트(내장 함수 ord()의 결과)를 사용해 사전식으로 비교합니다. [3]
문자열과 이진 시퀀스는 직접 비교될 수 없습니다.
시퀀스(tuple, list 또는 range 인스턴스)는 각 타입 내부에서만 비교될 수 있으며, range는 순서 비교를 지원하지 않는다는 제한이 있습니다. 이 타입들 간의 동등 비교는 같지 않음으로 이어지고, 이 타입들 간의 순서 비교는 TypeError를 발생시킵니다.
시퀀스는 대응하는 요소의 비교를 사용해 사전식으로 비교합니다. 내장 컨테이너는 일반적으로 동일한 객체가 자기 자신과 같다고 가정합니다. 이를 통해 동일한 객체에 대한 동등성 테스트를 건너뛰어 성능을 개선하고 내부 불변을 유지할 수 있습니다.
내장 컬렉션 간의 사전식 비교는 다음과 같이 동작합니다:
두 컬렉션이 같다고 비교되려면 같은 타입이어야 하고, 길이가 같아야 하며, 각 대응 요소 쌍이 같다고 비교되어야 합니다(예: [1,2] == (1,2)는 타입이 같지 않으므로 거짓).
순서 비교를 지원하는 컬렉션은 첫 번째로 같지 않은 요소와 같은 순서로 정렬됩니다(예: [1,2,x] <= [1,2,y]는 x <= y와 같은 값을 가집니다). 대응 요소가 존재하지 않으면 더 짧은 컬렉션이 먼저 정렬됩니다(예: [1,2] < [1,2,3]은 참).
매핑(dict 인스턴스)은 같은 (key, value) 쌍을 가질 경우에만 같다고 비교됩니다. 키와 값의 동등 비교는 반사성을 강제합니다.
순서 비교(<, >, <=, >=)는 TypeError를 발생시킵니다.
집합(set 또는 frozenset 인스턴스)은 타입 내부와 타입 간에 비교될 수 있습니다.
이는 순서 비교 연산자를 부분집합·초집합 테스트를 의미하도록 정의합니다. 그 관계는 전체 순서를 정의하지 않습니다(예: 두 집합 {1,2}와 {2,3}은 같지도, 서로의 부분집합도, 서로의 초집합도 아닙니다). 따라서 집합은 전체 순서에 의존하는 함수(예: min(), max(), sorted()는 집합 목록을 입력으로 주면 정의되지 않은 결과를 산출합니다)에 적절한 인수가 아닙니다.
집합의 비교는 요소의 반사성을 강제합니다.
대부분의 다른 내장 타입은 구현된 비교 메서드가 없으므로 기본 비교 동작을 상속합니다.
비교 동작을 사용자화하는 사용자 정의 클래스는 가능하면 몇 가지 일관성 규칙을 따라야 합니다:
동등 비교는 반사적이어야 합니다. 즉 동일한 객체는 같다고 비교되어야 합니다:
x is y는 x == y를 함의
비교는 대칭적이어야 합니다. 즉 다음 표현식은 같은 결과를 가져야 합니다:
x == y 그리고 y == x
x != y 그리고 y != x
x < y 그리고 y > x
x <= y 그리고 y >= x
비교는 추이적(transitive)이어야 합니다. 다음 (완전하지 않은) 예들이 이를 보여줍니다:
x > y and y > z는 x > z를 함의
x < y and y <= z는 x < z를 함의
역 비교는 불리언 부정이어야 합니다. 즉 다음 표현식은 같은 결과를 가져야 합니다:
x == y 그리고 not x != y
x < y 그리고 not x >= y (전체 순서에 대해)
x > y 그리고 not x <= y (전체 순서에 대해)
마지막 두 표현식은 전체 순서가 있는 컬렉션(예: 시퀀스에는 적용되지만 집합이나 매핑에는 적용되지 않음)에 적용됩니다. @~functools.total_ordering 데코레이터도 참조하세요.
hash() 결과는 동등성과 일관되어야 합니다. 같은 객체는 같은 해시 값을 가지거나 해시 불가능으로 표시되어야 합니다.
Python은 이러한 일관성 규칙을 강제하지 않습니다. 사실 not-a-number 값은 이 규칙을 따르지 않는 예입니다.
6.10.2. 멤버십 테스트 연산 (Membership test operations)
in과 not in 연산자는 멤버십을 테스트합니다. x in s는 x가 s의 멤버이면 True로, 그렇지 않으면 False로 평가됩니다. x not in s는 x in s의 부정을 반환합니다. 모든 내장 시퀀스와 집합 타입이 이를 지원하며 딕셔너리도 지원합니다. 딕셔너리에서 in은 주어진 키가 있는지 테스트합니다. list, tuple, set, frozenset, dict, collections.deque 같은 컨테이너 타입에서 x in y 표현식은 any(x is e or x == e for e in y)와 동등합니다.
문자열과 bytes 타입의 경우 x in y는 x가 y의 부분 문자열일 때만 True입니다. 동등한 테스트는 y.find(x) != -1입니다. 빈 문자열은 항상 다른 문자열의 부분 문자열로 간주되므로 "" in "abc"는 True를 반환합니다.
__contains__() 메서드를 정의하는 사용자 정의 클래스의 경우 x in y는 y.__contains__(x)가 참 값을 반환하면 True를, 그렇지 않으면 False를 반환합니다.
__contains__()를 정의하지 않지만 __iter__()를 정의하는 사용자 정의 클래스의 경우, y를 반복하는 동안 x is z or x == z 표현식이 참인 어떤 값 z가 만들어지면 x in y는 True입니다. 반복 중에 예외가 발생하면 in이 그 예외를 발생시킨 것과 같습니다.
마지막으로 구식 반복 프로토콜이 시도됩니다. 클래스가 __getitem__()을 정의하면, x is y[i] or x == y[i]인 음이 아닌 정수 인덱스 i가 존재하고 더 낮은 정수 인덱스가 IndexError 예외를 발생시키지 않을 때만 x in y는 True입니다. (다른 예외가 발생하면 in이 그 예외를 발생시킨 것과 같습니다.)
not in 연산자는 in의 역 참 값으로 정의됩니다.
6.10.3. 정체성 비교 (Identity comparisons)
is와 is not 연산자는 객체의 정체성을 테스트합니다. x is y는 x와 y가 같은 객체일 때만 참입니다. 객체의 정체성은 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
불리언 연산의 맥락에서, 그리고 표현식이 제어 흐름 문에서 사용될 때, 다음 값들은 거짓으로 해석됩니다: False, None, 모든 타입의 숫자 0, 그리고 빈 문자열과 컨테이너(문자열, 튜플, 리스트, 딕셔너리, 집합, frozenset 포함). 다른 모든 값은 참으로 해석됩니다. 사용자 정의 객체는 __bool__() 메서드를 제공해 참 값을 사용자화할 수 있어요.
not 연산자는 인수가 거짓이면 True를, 그렇지 않으면 False를 산출합니다.
x and y 표현식은 먼저 x를 평가합니다. x가 거짓이면 그 값이 반환되고, 그렇지 않으면 y가 평가되어 결과 값이 반환됩니다.
x or y 표현식은 먼저 x를 평가합니다. x가 참이면 그 값이 반환되고, 그렇지 않으면 y가 평가되어 결과 값이 반환됩니다.
and와 or 모두 반환하는 값과 타입을 False와 True로 제한하지 않고, 마지막으로 평가된 인수를 반환한다는 점에 주의하세요. 이는 때때로 유용합니다. 예를 들어 s가 비어 있으면 기본값으로 대체되어야 하는 문자열이라면 s or 'foo' 표현식이 원하는 값을 산출합니다. not은 새 값을 만들어야 하므로 인수 타입에 관계없이 불리언 값을 반환합니다(예: not 'foo'는 ''가 아니라 False를 만듭니다).
6.12. 할당 표현식 (Assignment expressions)
assignment_expression: [identifier ":="] expression
할당 표현식(때로는 "named expression" 또는 "walrus"라고도 함)은 expression을 identifier에 할당하면서도 expression의 값을 반환합니다.
흔한 사용 사례 중 하나는 정규 표현식 매칭을 다룰 때입니다:
if matching := pattern.search(data):
do_something(matching)
또는 파일 스트림을 청크 단위로 처리할 때:
while chunk := file.read(9000):
process(chunk)
할당 표현식은 표현식 문으로 사용될 때와 슬라이싱, 조건부, lambda, 키워드 인수, 컴프리헨션-if 표현식의 하위 표현식으로 사용될 때, 그리고 assert, with, assignment 문에서 사용될 때 괄호로 둘러싸야 합니다. 사용할 수 있는 다른 모든 곳에서는 if와 while 문을 포함해 괄호가 필요하지 않습니다.
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
조건부 표현식(때로는 "삼항 연산자"라고도 함)은 if-else 문의 대안입니다. 표현식이므로 값을 반환하고 하위 표현식으로 나타날 수 있습니다.
x if C else y 표현식은 x가 아니라 조건 C를 먼저 평가합니다. C가 참이면 x가 평가되어 그 값이 반환되고, 그렇지 않으면 y가 평가되어 그 값이 반환됩니다.
조건부 표현식에 대한 자세한 내용은 PEP 308을 참조하세요.
6.14. 람다 (Lambdas)
lambda_expr: "lambda" [parameter_list] ":" expression
람다 표현식(때로는 람다 형식)은 익명 함수를 만드는 데 사용됩니다. lambda parameters: expression 표현식은 함수 객체를 산출합니다. 이름 없는 객체는 다음과 같이 정의된 함수 객체처럼 동작합니다:
def <lambda>(parameters):
return expression
매개변수 목록의 구문은 Function definitions 섹션을 참조하세요. 람다 표현식으로 만든 함수는 문(statement)이나 주석(annotation)을 포함할 수 없다는 점에 주의하세요.
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]
리스트 또는 집합 표시의 일부인 경우를 제외하고, 최소 하나의 쉼표를 포함하는 표현식 목록은 튜플을 산출합니다. 튜플의 길이는 목록의 표현식 수입니다. 표현식은 왼쪽에서 오른쪽으로 평가됩니다.
별표 *는 *반복 가능 언패킹(iterable unpacking)*을 나타냅니다. 그 피연산자는 반복 가능해야 합니다. 반복 가능 객체는 일련의 항목으로 확장되며, 이 항목들은 언패킹 지점에서 새 튜플, 리스트 또는 집합에 포함됩니다.
Added in version 3.5: 표현식 목록에서의 반복 가능 언패킹, 원래 PEP 448이 제안.
Added in version 3.11: 표현식 목록의 어떤 항목이든 별표가 될 수 있습니다. PEP 646 참조.
후행 쉼표는 1, 같은 한 항목 튜플을 만드는 데만 필요합니다. 다른 모든 경우에는 선택 사항입니다. 후행 쉼표가 없는 단일 표현식은 튜플을 만들지 않고 그 표현식의 값을 산출합니다. (빈 튜플을 만들려면 빈 괄호 쌍을 사용하세요: ().)
6.16. 평가 순서 (Evaluation order)
Python은 표현식을 왼쪽에서 오른쪽으로 평가합니다. 할당을 평가할 때는 오른쪽이 왼쪽보다 먼저 평가된다는 점에 주의하세요.
다음 줄들에서 표현식은 접미사의 산술 순서로 평가됩니다:
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. 연산자 우선순위 (Operator precedence)
다음 표는 Python의 연산자 우선순위를 높은 것(가장 강하게 결합)에서 낮은 것(가장 약하게 결합)으로 요약합니다. 같은 상자 안의 연산자는 같은 우선순위를 가집니다. 구문이 명시적으로 주어지지 않으면 연산자는 이항입니다. 같은 상자 안의 연산자는 왼쪽에서 오른쪽으로 결합합니다(거듭제곱과 조건부 표현식은 예외로, 오른쪽에서 왼쪽으로 결합합니다).
비교, 멤버십 테스트, 정체성 테스트는 모두 같은 우선순위를 가지며 Comparisons 섹션에서 설명한 왼쪽에서 오른쪽 연결(chain) 기능을 가진다는 점에 주의하세요.
| Operator | Description |
|---|---|
(expressions...), [expressions...], {key: value...}, {expressions...} |
Binding or parenthesized expression, list display, dictionary display, set display |
x[index], x[index:index] x(arguments...), x.attribute |
Subscription (including slicing), call, attribute reference |
await x |
Await expression |
** |
Exponentiation [5] |
+x, -x, ~x |
Positive, negative, bitwise NOT |
*, @, /, //, % |
Multiplication, matrix multiplication, division, floor division, remainder [6] |
+, - |
Addition and subtraction |
<<, >> |
Shifts |
& |
Bitwise AND |
^ |
Bitwise XOR |
| ` | ` |
in, not in, is, is not, <, <=, >, >=, !=, == |
Comparisons, including membership tests and identity tests |
not x |
Boolean NOT |
and |
Boolean AND |
or |
Boolean OR |
if – else |
Conditional expression |
lambda |
Lambda expression |
:= |
Assignment expression |
Footnotes
[1]
수학적으로 abs(x%y) < abs(y)가 참인 반면, float에서는 반올림 오차 때문에 수치적으로 참이 아닐 수 있어요. 예를 들어 Python float가 IEEE 754 배정밀도 숫자인 플랫폼을 가정하면, -1e-100 % 1e100이 1e100과 같은 부호를 갖기 위해 계산된 결과는 -1e-100 + 1e100이며, 이는 수치적으로 정확히 1e100과 같습니다. math.fmod() 함수는 대신 첫 번째 인수의 부호와 일치하는 결과를 반환하므로 이 경우 -1e-100을 반환합니다. 어떤 접근이 더 적절한지는 응용에 따라 다릅니다.
[2]
x가 y의 정확한 정수 배수에 매우 가까우면, 반올림 때문에 x//y가 (x-x%y)//y보다 하나 클 수 있어요. 그런 경우 Python은 divmod(x,y)[0] * y + x % y가 x에 매우 가깝도록 유지하기 위해 후자 결과를 반환합니다.
[3]
유니코드 표준은 코드 포인트(code points) (예: U+0041)와 추상 문자(abstract characters) (예: "LATIN CAPITAL LETTER A")를 구분합니다. 유니코드의 대부분의 추상 문자는 하나의 코드 포인트로만 표현되지만, 하나 이상의 코드 포인트 시퀀스로도 표현될 수 있는 추상 문자도 있습니다. 예를 들어 추상 문자 "LATIN CAPITAL LETTER C WITH CEDILLA"는 코드 위치 U+00C7의 단일 precomposed character로 표현되거나, 코드 위치 U+0043(LATIN CAPITAL LETTER C)의 base character 뒤에 코드 위치 U+0327(COMBINING CEDILLA)의 combining character가 오는 시퀀스로 표현될 수 있습니다.
문자열에 대한 비교 연산자는 유니코드 코드 포인트 수준에서 비교합니다. 이는 인간에게 직관에 반할 수 있어요. 예를 들어 "\u00C7" == "\u0043\u0327"는 두 문자열이 같은 추상 문자 "LATIN CAPITAL LETTER C WITH CEDILLA"를 나타내더라도 False입니다.
추상 문자 수준(즉 인간에게 직관적인 방식)에서 문자열을 비교하려면 unicodedata.normalize()를 사용하세요.
[4]
자동 가비지 컬렉션, 자유 목록, 디스크립터의 동적 성질 때문에 인스턴스 메서드나 상수 간의 비교를 포함하는 is 연산자의 특정 사용에서 겉보기에 이상한 동작을 발견할 수 있어요. 자세한 내용은 해당 문서를 확인하세요.
[5]
거듭제곱 연산자 **는 오른쪽의 산술 또는 비트 단항 연산자보다 덜 강하게 결합합니다. 즉 2**-1은 0.5입니다.
[6]
% 연산자는 문자열 형식화에도 사용됩니다. 같은 우선순위가 적용됩니다.
더 알아보기 (Learn more)
Python 언어 참조의 다른 표현식 관련 문서와 표준 라이브러리 문서를 참고하세요.