8. Складені висловлювання¶
Складені висловлювання містять (групи) інші висловлювання; вони певним чином впливають або контролюють виконання цих інших операторів. Загалом складені висловлювання охоплюють кілька рядків, хоча в простих варіантах ціле складене висловлювання може міститися в одному рядку.
Оператори if
, while
і for
реалізують традиційні конструкції потоку керування. try
визначає обробники винятків та/або код очищення для групи операторів, тоді як оператор with
дозволяє виконувати код ініціалізації та фіналізації навколо блоку коду. Визначення функцій і класів також є синтаксично складеними висловлюваннями.
Складений оператор складається з одного або кількох «речень». Речення складається із заголовка та «набору». Усі заголовки речень певного складеного оператора мають однаковий рівень відступу. Кожен заголовок пропозиції починається з унікального ключового слова та закінчується двокрапкою. Набір — це група висловлювань, керованих реченням. Набір може складатися з одного або кількох простих операторів, розділених крапкою з комою, у тому самому рядку, що й заголовок, після двокрапки заголовка, або це може бути один чи більше операторів із відступом у наступних рядках. Лише остання форма набору може містити вкладені складені оператори; наступне є незаконним, здебільшого тому, що було б незрозуміло, до якого пункту if
належало б таке положення else
:
if test1: if test2: print(x)
Також зауважте, що в цьому контексті крапка з комою зв’язується сильніше, ніж двокрапка, тому в наступному прикладі виконуються або всі, або жоден із викликів print()
:
if x < y < z: print(x); print(y); print(z)
Підведення підсумків:
compound_stmt ::=if_stmt
|while_stmt
|for_stmt
|try_stmt
|with_stmt
|match_stmt
|funcdef
|classdef
|async_with_stmt
|async_for_stmt
|async_funcdef
suite ::=stmt_list
NEWLINE | NEWLINE INDENTstatement
+ DEDENT statement ::=stmt_list
NEWLINE |compound_stmt
stmt_list ::=simple_stmt
(";"simple_stmt
)* [";"]
Зауважте, що оператори завжди закінчуються на NEWLINE
, після якого, можливо, йде DEDENT
. Також зауважте, що необов’язкові речення продовження завжди починаються з ключового слова, яке не може розпочинати оператор, тому немає ніяких двозначностей (проблему «висячих else
» вирішено в Python, вимагаючи вкладених операторів if
з відступом).
Форматування правил граматики в наступних розділах розміщує кожне речення в окремому рядку для ясності.
8.1. Оператор if
¶
Оператор if
використовується для умовного виконання:
if_stmt ::= "if"assignment_expression
":"suite
("elif"assignment_expression
":"suite
)* ["else" ":"suite
]
Він вибирає точно один із наборів, обчислюючи вирази один за іншим, доки один не буде визнаний істинним (див. розділ Логічні операції для визначення істинного та хибного); тоді цей набір виконується (і жодна інша частина оператора if
не виконується і не оцінюється). Якщо всі вирази хибні, виконується набір пропозиції else
, якщо вона є.
8.2. Оператор while
¶
Інструкція while
використовується для повторного виконання, доки вираз є істинним:
while_stmt ::= "while"assignment_expression
":"suite
["else" ":"suite
]
Це багаторазово перевіряє вираз і, якщо воно вірне, виконує перший набір; якщо вираз є хибним (що може бути першим, коли його перевіряють), набір пропозиції else
виконується, і цикл припиняється.
Інструкція break
, виконана в першому наборі, завершує цикл без виконання набору речень else
. Інструкція continue
, виконана в першому наборі, пропускає решту пакета і повертається до перевірки виразу.
8.3. Оператор for
¶
Оператор for
використовується для повторення елементів послідовності (таких як рядок, кортеж або список) або іншого ітерованого об’єкта:
for_stmt ::= "for"target_list
"in"starred_list
":"suite
["else" ":"suite
]
The starred_list
expression is evaluated once; it should yield an
iterable object. An iterator is created for that iterable.
The first item provided
by the iterator is then assigned to the target list using the standard
rules for assignments (see Заяви про призначення), and the suite is executed. This
repeats for each item provided by the iterator. When the iterator is exhausted,
the suite in the else
clause,
if present, is executed, and the loop terminates.
Інструкція break
, виконана в першому наборі, завершує цикл без виконання набору речень else
. Інструкція continue
, виконана в першому наборі, пропускає решту набору і продовжує з наступним елементом або з пропозицією else
, якщо наступного елемента немає.
Цикл for виконує призначення змінним у цільовому списку. Це перезаписує всі попередні призначення цим змінним, включаючи ті, що зроблені в наборі циклу for:
for i in range(10):
print(i)
i = 5 # this will not affect the for-loop
# because i will be overwritten with the next
# index in the range
Names in the target list are not deleted when the loop is finished, but if the
sequence is empty, they will not have been assigned to at all by the loop. Hint:
the built-in type range()
represents immutable arithmetic sequences of integers.
For instance, iterating range(3)
successively yields 0, 1, and then 2.
Змінено в версії 3.11: Starred elements are now allowed in the expression list.
8.4. Оператор try
¶
The try
statement specifies exception handlers and/or cleanup code
for a group of statements:
try_stmt ::=try1_stmt
|try2_stmt
|try3_stmt
try1_stmt ::= "try" ":"suite
("except" [expression
["as"identifier
]] ":"suite
)+ ["else" ":"suite
] ["finally" ":"suite
] try2_stmt ::= "try" ":"suite
("except" "*"expression
["as"identifier
] ":"suite
)+ ["else" ":"suite
] ["finally" ":"suite
] try3_stmt ::= "try" ":"suite
"finally" ":"suite
Додаткову інформацію про винятки можна знайти в розділі Винятки, а інформацію про використання оператора raise
для створення винятків можна знайти в розділі Оператор raise.
8.4.1. except
clause¶
The except
clause(s) specify one or more exception handlers. When no
exception occurs in the try
clause, no exception handler is executed.
When an exception occurs in the try
suite, a search for an exception
handler is started. This search inspects the except
clauses in turn
until one is found that matches the exception.
An expression-less except
clause, if present, must be last;
it matches any exception.
For an except
clause with an expression, the
expression must evaluate to an exception type or a tuple of exception types.
The raised exception matches an except
clause whose expression evaluates
to the class or a non-virtual base class of the exception object,
or to a tuple that contains such a class.
If no except
clause matches the exception,
the search for an exception handler
continues in the surrounding code and on the invocation stack. [1]
If the evaluation of an expression
in the header of an except
clause raises an exception,
the original search for a handler is canceled and a search starts for
the new exception in the surrounding code and on the call stack (it is treated
as if the entire try
statement raised the exception).
When a matching except
clause is found,
the exception is assigned to the target
specified after the as
keyword in that except
clause,
if present, and the except
clause’s suite is executed.
All except
clauses must have an executable block.
When the end of this block is reached, execution continues
normally after the entire try
statement.
(This means that if two nested handlers exist for the same exception,
and the exception occurs in the try
clause of the inner handler,
the outer handler will not handle the exception.)
When an exception has been assigned using as target
, it is cleared at the
end of the except
clause. This is as if
except E as N:
foo
було перекладено на:
except E as N:
try:
foo
finally:
del N
This means the exception must be assigned to a different name to be able to
refer to it after the except
clause.
Exceptions are cleared because with the
traceback attached to them, they form a reference cycle with the stack frame,
keeping all locals in that frame alive until the next garbage collection occurs.
Before an except
clause’s suite is executed,
the exception is stored in the sys
module, where it can be accessed
from within the body of the except
clause by calling
sys.exception()
. When leaving an exception handler, the exception
stored in the sys
module is reset to its previous value:
>>> print(sys.exception())
None
>>> try:
... raise TypeError
... except:
... print(repr(sys.exception()))
... try:
... raise ValueError
... except:
... print(repr(sys.exception()))
... print(repr(sys.exception()))
...
TypeError()
ValueError()
TypeError()
>>> print(sys.exception())
None
8.4.2. except*
clause¶
The except*
clause(s) are used for handling
ExceptionGroup
s. The exception type for matching is interpreted as in
the case of except
, but in the case of exception groups we can have
partial matches when the type matches some of the exceptions in the group.
This means that multiple except*
clauses can execute,
each handling part of the exception group.
Each clause executes at most once and handles an exception group
of all matching exceptions. Each exception in the group is handled by at most
one except*
clause, the first that matches it.
>>> try:
... raise ExceptionGroup("eg",
... [ValueError(1), TypeError(2), OSError(3), OSError(4)])
... except* TypeError as e:
... print(f'caught {type(e)} with nested {e.exceptions}')
... except* OSError as e:
... print(f'caught {type(e)} with nested {e.exceptions}')
...
caught <class 'ExceptionGroup'> with nested (TypeError(2),)
caught <class 'ExceptionGroup'> with nested (OSError(3), OSError(4))
+ Exception Group Traceback (most recent call last):
| File "<stdin>", line 2, in <module>
| ExceptionGroup: eg
+-+---------------- 1 ----------------
| ValueError: 1
+------------------------------------
Any remaining exceptions that were not handled by any except*
clause are re-raised at the end, along with all exceptions that were
raised from within the except*
clauses. If this list contains
more than one exception to reraise, they are combined into an exception
group.
If the raised exception is not an exception group and its type matches
one of the except*
clauses, it is caught and wrapped by an
exception group with an empty message string.
>>> try:
... raise BlockingIOError
... except* BlockingIOError as e:
... print(repr(e))
...
ExceptionGroup('', (BlockingIOError()))
An except*
clause must have a matching expression; it cannot be except*:
.
Furthermore, this expression cannot contain exception group types, because that would
have ambiguous semantics.
It is not possible to mix except
and except*
in the same try
.
break
, continue
and return
cannot appear in an except*
clause.
8.4.3. else
clause¶
Необов’язкова пропозиція else
виконується, якщо потік керування виходить із набору try
, не було викликано винятків і немає return
, continue
або Інструкція break
була виконана. Винятки в пункті else
не обробляються попередніми пунктами except
.
8.4.4. finally
clause¶
If finally
is present, it specifies a „cleanup“ handler. The
try
clause is executed, including any except
and
else
clauses. If an exception occurs in any of the clauses and is
not handled, the exception is temporarily saved. The finally
clause
is executed. If there is a saved exception it is re-raised at the end of the
finally
clause. If the finally
clause raises another
exception, the saved exception is set as the context of the new exception.
If the finally
clause executes a return
, break
or continue
statement, the saved exception is discarded:
>>> def f():
... try:
... 1/0
... finally:
... return 42
...
>>> f()
42
The exception information is not available to the program during execution of
the finally
clause.
When a return
, break
or continue
statement is
executed in the try
suite of a try
…finally
statement, the finally
clause is also executed „on the way out.“
The return value of a function is determined by the last return
statement executed. Since the finally
clause always executes, a
return
statement executed in the finally
clause will
always be the last one executed:
>>> def foo():
... try:
... return 'try'
... finally:
... return 'finally'
...
>>> foo()
'finally'
Змінено в версії 3.8: Prior to Python 3.8, a continue
statement was illegal in the
finally
clause due to a problem with the implementation.
8.5. Оператор with
¶
Оператор with
використовується для обгортання виконання блоку методами, визначеними контекстним менеджером (див. розділ З менеджерами контексту операторів). Це дозволяє інкапсулювати загальні try
…except
…finally
моделі використання для зручного повторного використання.
with_stmt ::= "with" ( "("with_stmt_contents
","? ")" |with_stmt_contents
) ":"suite
with_stmt_contents ::=with_item
(","with_item
)* with_item ::=expression
["as"target
]
Виконання оператора with
з одним «елементом» відбувається наступним чином:
Контекстний вираз (вираз, поданий у
with_item
) обчислюється для отримання контекстного менеджера.The context manager’s
__enter__()
is loaded for later use.The context manager’s
__exit__()
is loaded for later use.The context manager’s
__enter__()
method is invoked.If a target was included in the
with
statement, the return value from__enter__()
is assigned to it.Примітка
The
with
statement guarantees that if the__enter__()
method returns without an error, then__exit__()
will always be called. Thus, if an error occurs during the assignment to the target list, it will be treated the same as an error occurring within the suite would be. See step 7 below.Сюїта виконана.
The context manager’s
__exit__()
method is invoked. If an exception caused the suite to be exited, its type, value, and traceback are passed as arguments to__exit__()
. Otherwise, threeNone
arguments are supplied.If the suite was exited due to an exception, and the return value from the
__exit__()
method was false, the exception is reraised. If the return value was true, the exception is suppressed, and execution continues with the statement following thewith
statement.If the suite was exited for any reason other than an exception, the return value from
__exit__()
is ignored, and execution proceeds at the normal location for the kind of exit that was taken.
Наступний код:
with EXPRESSION as TARGET:
SUITE
семантично еквівалентний:
manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
try:
TARGET = value
SUITE
except:
if not exit(manager, *sys.exc_info()):
raise
else:
exit(manager, None, None, None)
З більш ніж одним елементом менеджери контексту обробляються так, ніби кілька операторів with
були вкладеними:
with A() as a, B() as b:
SUITE
семантично еквівалентний:
with A() as a:
with B() as b:
SUITE
Ви також можете писати багатоелементні контекстні менеджери в кілька рядків, якщо елементи оточені дужками. Наприклад:
with (
A() as a,
B() as b,
):
SUITE
Змінено в версії 3.1: Підтримка кількох контекстних виразів.
Змінено в версії 3.10: Підтримка використання групування дужок для розбиття оператора на кілька рядків.
8.6. Оператор match
¶
Added in version 3.10.
Оператор match використовується для зіставлення шаблону. Синтаксис:
match_stmt ::= 'match'subject_expr
":" NEWLINE INDENTcase_block
+ DEDENT subject_expr ::=star_named_expression
","star_named_expressions
? |named_expression
case_block ::= 'case'patterns
[guard
] ":"block
Примітка
У цьому розділі використовуються одинарні лапки для позначення м’яких ключових слів.
Зіставлення шаблону приймає шаблон як вхідні дані (після case
) і значення теми (після match
). Шаблон (який може містити підшаблони) зіставляється зі значенням теми. Результати:
Успіх або невдача збігу (також називається успішним або невдалим шаблоном).
Можливе прив’язування відповідних значень до імені. Передумови для цього обговорюються нижче.
Ключові слова match
і case
є м’якими ключовими словами.
Дивись також
8.6.1. Огляд¶
Ось огляд логічної послідовності оператора збігу:
Вираз суб’єкта
subject_expr
обчислюється та отримується результуюче значення предмета. Якщо вираз теми містить кому, кортеж створюється за допомогою стандартних правил.Кожен шаблон у
case_block
намагається зіставити зі значенням теми. Конкретні правила успіху чи невдачі описані нижче. Спроба збігу також може пов’язати деякі або всі окремі імена в шаблоні. Точні правила зв’язування шаблону залежать від типу шаблону та вказані нижче. Прив’язки імен, зроблені під час успішного збігу шаблону, переживають виконаний блок і можуть використовуватися після оператора збігу.Примітка
Під час невдалих збігів шаблонів деякі підшаблони можуть бути успішними. Не покладайтеся на прив’язки, зроблені для невдалого матчу. І навпаки, не покладайтеся на те, що змінні залишаться незмінними після невдалого збігу. Точна поведінка залежить від реалізації та може відрізнятися. Це навмисне рішення, яке дозволяє оптимізувати різні реалізації.
Якщо шаблон успішний, відповідний охоронець (якщо присутній) оцінюється. У цьому випадку всі прив’язки імен гарантовано відбулися.
Якщо guard оцінює як true або відсутній, виконується
block
всерединіcase_block
.Інакше виконується спроба наступного
case_block
, як описано вище.Якщо немає інших блоків регістру, оператор збігу завершується.
Примітка
Зазвичай користувачі ніколи не повинні покладатися на шаблон, що оцінюється. Залежно від реалізації, інтерпретатор може кешувати значення або використовувати інші оптимізації, які пропускають повторні оцінки.
Зразок заяви про відповідність:
>>> flag = False
>>> match (100, 200):
... case (100, 300): # Mismatch: 200 != 300
... print('Case 1')
... case (100, 200) if flag: # Successful match, but guard fails
... print('Case 2')
... case (100, y): # Matches and binds y to 200
... print(f'Case 3, y: {y}')
... case _: # Pattern not attempted
... print('Case 4, I match anything!')
...
Case 3, y: 200
У цьому випадку if flag
є охороною. Докладніше про це читайте в наступному розділі.
8.6.2. Охоронці¶
guard ::= "if" named_expression
guard
(який є частиною case
) має бути успішним для виконання коду всередині блоку case
. Він приймає форму: if
, після якого йде вираз.
Логічний послідовність блоку case
з guard
наступна:
Переконайтеся, що шаблон у блоці
case
виконано успішно. Якщо шаблон не вдається,guard
не оцінюється, і перевіряється наступнийcase
блок.Якщо шаблон вдався, оцініть
guard
.Якщо умова
guard
оцінюється як істинна, вибирається блок регістру.Якщо умова
guard
оцінюється як false, блок регістру не вибрано.Якщо
охоронець
викликає виняток під час оцінки, виняток з’являється.
Охоронцям дозволено мати побічні ефекти, оскільки вони є виразами. Оцінка Guard повинна проходити від першого до останнього блоку регістрів, по одному, пропускаючи блоки регістрів, шаблон(и) яких не всі є успішними. (Тобто оцінка охорони має відбуватися в порядку.) Оцінка охорони має припинитися, коли вибрано блок справи.
8.6.3. Незаперечні блоки випадків¶
Незаперечний блок регістрів — це блок регістрів, що відповідає всім регістрам. Інструкція збігу може мати щонайбільше один неспростовний блок регістру, і він має бути останнім.
Блок футляра вважається незаперечним, якщо він не має захисного елемента і його візерунок є неспростовним. Патерн вважається неспростовним, якщо ми можемо довести лише з його синтаксису, що він завжди матиме успіх. Незаперечними є лише такі закономірності:
AS Patterns, ліва сторона якого неспростовна
АБО Шаблони, що містить принаймні один неспростовний шаблон
в дужках неспростовні закономірності
8.6.4. Візерунки¶
Примітка
У цьому розділі використовуються граматичні нотації поза стандартними EBNF:
позначення
SEP.RULE+
є скороченням дляRULE (SEP RULE)*
нотація
!RULE
є скороченням для негативного твердження попереднього перегляду
Синтаксис верхнього рівня для патернів
такий:
patterns ::=open_sequence_pattern
|pattern
pattern ::=as_pattern
|or_pattern
closed_pattern ::= |literal_pattern
|capture_pattern
|wildcard_pattern
|value_pattern
|group_pattern
|sequence_pattern
|mapping_pattern
|class_pattern
Наведені нижче описи включатимуть опис «у простих термінах» того, що робить шаблон для цілей ілюстрації (заслуга Реймонда Геттінгера за документ, який надихнув більшість описів). Зауважте, що ці описи наведено лише для ілюстрації та можуть не відображати базову реалізацію. Крім того, вони не охоплюють усіх дійсних форм.
8.6.4.1. АБО Шаблони¶
Шаблон АБО — це два або більше шаблонів, розділених вертикальними рисками |
. Синтаксис:
or_pattern ::= "|".closed_pattern
+
Лише остаточний підшаблон може бути irrefutable, і кожен підшаблон повинен пов’язувати однаковий набір імен, щоб уникнути двозначності.
Шаблон АБО зіставляє кожен зі своїх підшаблонів по черзі зі значенням суб’єкта, поки один не досягне успіху. Потім шаблон АБО вважається успішним. В іншому випадку, якщо жоден із підшаблонів не вдасться, шаблон АБО буде невдалим.
Простіше кажучи, P1 | P2 | ...
намагатиметься знайти відповідність P1
, якщо це не вдасться, вона спробує знайти P2
, успішно негайно, якщо будь-який з них вдасться, інакше не вдасться.
8.6.4.2. AS Patterns¶
Шаблон AS відповідає шаблону АБО ліворуч від ключового слова as
щодо теми. Синтаксис:
as_pattern ::=or_pattern
"as"capture_pattern
If the OR pattern fails, the AS pattern fails. Otherwise, the AS pattern binds
the subject to the name on the right of the as keyword and succeeds.
capture_pattern
cannot be a _
.
Простіше кажучи, P as NAME
співпадатиме з P
, і в разі успіху буде встановлено NAME = <subject>
.
8.6.4.3. Літеральні візерунки¶
Шаблон літералів відповідає більшості літералів у Python. Синтаксис:
literal_pattern ::=signed_number
|signed_number
"+" NUMBER |signed_number
"-" NUMBER |strings
| "None" | "True" | "False" signed_number ::= ["-"] NUMBER
Правило рядки
і токен ЧИСЛО
визначено в стандартній граматиці Python. Підтримуються рядки в потрійних лапках. Підтримуються необроблені рядки та рядки байтів. f-strings не підтримуються.
Форми число_знак '+' ЧИСЛО
і число_знак '-' ЧИСЛО
призначені для вираження комплексних чисел; вони вимагають дійсного числа зліва та уявного числа справа. наприклад 3 + 4j
.
Простіше кажучи, LITERAL
буде успішним, лише якщо <subject> == LITERAL
. Для синглтонів None
, True
і False
використовується оператор is
.
8.6.4.4. Захоплення шаблонів¶
Шаблон захоплення прив’язує значення теми до імені. Синтаксис:
capture_pattern ::= !'_' NAME
Одне підкреслення _
не є шаблоном захоплення (це те, що !'_''
виражає). Натомість він розглядається як wildcard_pattern
.
У заданому шаблоні дане ім’я може бути пов’язане лише один раз. наприклад case x, x: ...
недійсний, тоді як case [x] | x: ...
дозволено.
Захоплення шаблонів завжди вдається. Зв’язування відповідає правилам області видимості, встановленим оператором виразу присвоєння в PEP 572; ім’я стає локальною змінною в найближчій області видимості функції, якщо немає відповідного оператора global
або nonlocal
.
Простіше кажучи, NAME
завжди матиме успіх і встановлюватиме NAME = <subject>
.
8.6.4.5. Шаблони підстановок¶
Шаблон підстановки завжди успішний (відповідає будь-чому) і не прив’язує жодного імені. Синтаксис:
wildcard_pattern ::= '_'
_
є м’яким ключовим словом у будь-якому шаблоні, але лише всередині шаблонів. Це ідентифікатор, як зазвичай, навіть у виразах теми match
, guard
s і case
блоків.
Простіше кажучи, _
завжди матиме успіх.
8.6.4.6. Шаблони цінностей¶
Шаблон значення представляє іменоване значення в Python. Синтаксис:
value_pattern ::=attr
attr ::=name_or_attr
"." NAME name_or_attr ::=attr
| NAME
Пунктирна назва в шаблоні шукається за допомогою стандартних Python правил розпізнавання імен. Шаблон виконується успішно, якщо знайдене значення порівнюється зі значенням предмета (з використанням оператора рівності ==
).
Простіше кажучи, NAME1.NAME2
буде успішним, лише якщо <subject> == NAME1.NAME2
Примітка
Якщо те саме значення зустрічається кілька разів у тому самому операторі збігу, інтерпретатор може кешувати перше знайдене значення та використовувати його повторно, а не повторювати той самий пошук. Цей кеш суворо прив’язаний до заданого виконання даного оператора відповідності.
8.6.4.7. Шаблони груп¶
Груповий шаблон дозволяє користувачам додавати дужки навколо шаблонів, щоб підкреслити передбачуване групування. В іншому випадку він не має додаткового синтаксису. Синтаксис:
group_pattern ::= "(" pattern
")"
Простіше кажучи, (P)
має той самий ефект, що P
.
8.6.4.8. Шаблони послідовності¶
Шаблон послідовності містить кілька підшаблонів, які потрібно зіставити з елементами послідовності. Синтаксис подібний до розпакування списку або кортежу.
sequence_pattern ::= "[" [maybe_sequence_pattern
] "]" | "(" [open_sequence_pattern
] ")" open_sequence_pattern ::=maybe_star_pattern
"," [maybe_sequence_pattern
] maybe_sequence_pattern ::= ",".maybe_star_pattern
+ ","? maybe_star_pattern ::=star_pattern
|pattern
star_pattern ::= "*" (capture_pattern
|wildcard_pattern
)
Немає різниці, якщо дужки або квадратні дужки використовуються для шаблонів послідовності (тобто (...)
проти [...]
).
Примітка
Один шаблон, укладений у дужки без кінцевої коми (наприклад, (3 | 4)
), є груповим шаблоном. У той час як один шаблон, укладений у квадратні дужки (наприклад, [3 | 4]
), все ще є шаблоном послідовності.
Щонайбільше один зірковий підшаблон може бути в шаблоні послідовності. Підшаблон зірки може з’являтися в будь-якій позиції. Якщо підшаблон зірки відсутній, шаблон послідовності є шаблоном послідовності фіксованої довжини; інакше це шаблон послідовності змінної довжини.
Нижче наведено логічний потік для зіставлення шаблону послідовності зі значенням предмета:
Якщо значення теми не є послідовністю [2], шаблон послідовності не виконується.
Якщо значення теми є екземпляром
str
,bytes
абоbytearray
, шаблон послідовності не виконується.Подальші кроки залежать від того, чи є шаблон послідовності фіксованою чи змінною довжиною.
Якщо шаблон послідовності має фіксовану довжину:
Якщо довжина предметної послідовності не дорівнює кількості підшаблонів, шаблон послідовності не вдається
Підшаблони в шаблоні послідовності зіставляються з відповідними елементами в послідовності предметів зліва направо. Зіставлення припиняється, як тільки підшаблон не вдається. Якщо всі підшаблони успішно відповідають їхньому відповідному елементу, шаблон послідовності вдається.
В іншому випадку, якщо шаблон послідовності має змінну довжину:
Якщо довжина предметної послідовності менша за кількість незіркових підшаблонів, шаблон послідовності не вдається.
Провідні незіркові підшаблони зіставляються з відповідними елементами, як для послідовностей фіксованої довжини.
Якщо попередній крок виконано успішно, підшаблон зірочки збігається зі списком, сформованим із решти предметних елементів, за винятком решти елементів, що відповідають підшаблонам без зірочки, які слідують за підшаблоном зірочки.
Решта підшаблонів без зірок зіставляються з відповідними предметними елементами, як для послідовності фіксованої довжини.
Примітка
Довжина предметної послідовності визначається через
len()
(тобто через__len__()
протокол). Ця довжина може бути кешована інтерпретатором подібним чином, як шаблони значень.
Простіше кажучи, [P1, P2, P3,
… , P <N> ]
збігається, лише якщо відбувається все наступне:
перевірка
<subject>
є послідовністюlen(subject) == <N>
P1
відповідає<subject> [0]
(зауважте, що цей збіг також може пов’язувати імена)P2
відповідає<subject> [1]
(зауважте, що цей збіг також може пов’язувати імена)… і так далі для відповідного шаблону/елемента.
8.6.4.9. Шаблони відображення¶
Шаблон зіставлення містить один або кілька шаблонів ключ-значення. Синтаксис подібний до побудови словника. Синтаксис:
mapping_pattern ::= "{" [items_pattern
] "}" items_pattern ::= ",".key_value_pattern
+ ","? key_value_pattern ::= (literal_pattern
|value_pattern
) ":"pattern
|double_star_pattern
double_star_pattern ::= "**"capture_pattern
Щонайбільше один шаблон подвійної зірки може бути в шаблоні відображення. Шаблон подвійної зірки має бути останнім підшаблоном у шаблоні відображення.
Дублікати ключів у шаблонах зіставлення заборонені. Повторювані ключі літералів викличуть SyntaxError
. Два ключі, які інакше мають однакові значення, викликають ValueError
під час виконання.
Нижче наведено логічний потік для зіставлення шаблону зіставлення зі значенням предмета:
Якщо значення предмета не є відображенням [3], шаблон відображення не виконується.
Якщо кожен ключ, поданий у шаблоні відображення, присутній у відображенні предмета, і шаблон для кожного ключа збігається з відповідним елементом відображення предмета, шаблон відображення є успішним.
Якщо в шаблоні відображення виявлено повторювані ключі, шаблон вважається недійсним.
SyntaxError
виникає для повторюваних літеральних значень; абоValueError
для іменованих ключів з тим самим значенням.
Примітка
Key-value pairs are matched using the two-argument form of the mapping
subject’s get()
method. Matched key-value pairs must already be present
in the mapping, and not created on-the-fly via __missing__()
or
__getitem__()
.
Простіше кажучи, {KEY1: P1, KEY2: P2, ... }
відповідає, лише якщо відбувається все наступне:
перевірка
<subject>
є відображеннямKEY1 in <subject>
P1
відповідає<subject>[KEY1]
… і так далі для відповідної пари КЛЮЧ/шаблон.
8.6.4.10. Шаблони класів¶
Шаблон класу представляє клас і його позиційні та ключові аргументи (якщо такі є). Синтаксис:
class_pattern ::=name_or_attr
"(" [pattern_arguments
","?] ")" pattern_arguments ::=positional_patterns
[","keyword_patterns
] |keyword_patterns
positional_patterns ::= ",".pattern
+ keyword_patterns ::= ",".keyword_pattern
+ keyword_pattern ::= NAME "="pattern
Те саме ключове слово не повинно повторюватися в шаблонах класів.
Нижче наведено логічний потік для зіставлення шаблону класу зі значенням предмета:
Якщо
name_or_attr
не є екземпляром вбудованогоtype
, викликатиTypeError
.Якщо значення теми не є екземпляром
name_or_attr
(перевірено черезisinstance()
), шаблон класу не вдається.Якщо аргументи шаблону відсутні, шаблон виконується успішно. В іншому випадку наступні кроки залежать від того, чи присутні шаблони ключових слів або позиційних аргументів.
Для ряду вбудованих типів (зазначених нижче) приймається один позиційний підшаблон, який відповідатиме всьому об’єкту; для цих типів шаблони ключових слів також працюють, як і для інших типів.
Якщо присутні лише шаблони ключових слів, вони обробляються таким чином, один за іншим:
I. Ключове слово шукається як атрибут теми.
Якщо це викликає виняток, відмінний від
AttributeError
, виняток з’являється.Якщо це викликає помилку
AttributeError
, шаблон класу стався невдало.В іншому випадку підшаблон, пов’язаний із шаблоном ключового слова, зіставляється зі значенням атрибута суб’єкта. Якщо це не вдається, шаблон класу не працює; якщо це вдається, відповідність переходить до наступного ключового слова.
II. Якщо всі шаблони ключових слів успішні, шаблон класу успішний.
Якщо присутні будь-які позиційні шаблони, вони перетворюються на шаблони ключових слів за допомогою атрибута
__match_args__
класуname_or_attr
перед відповідністю:I. Викликається еквівалент
getattr(cls, "__match_args__", ())
.Якщо це викликає виняток, виняток з’являється.
Якщо повернуте значення не є кортежем, перетворення не вдається, і виникає
TypeError
.Якщо є більше позиційних шаблонів, ніж
len(cls.__match_args__)
, виникаєTypeError
.В іншому випадку позиційний шаблон
i
перетворюється на шаблон ключового слова з використанням__match_args__[i]
як ключове слово.__match_args__[i]
має бути рядком; якщо ні, виникаєTypeError
.Якщо є повторювані ключові слова, виникає
TypeError
.
- II. Коли всі позиційні моделі буде перетворено на ключові слова,
відповідність відбувається так, якби були лише шаблони ключових слів.
Для наступних вбудованих типів обробка позиційних підшаблонів відрізняється:
These classes accept a single positional argument, and the pattern there is matched against the whole object rather than an attribute. For example
int(0|1)
matches the value0
, but not the value0.0
.
Простіше кажучи, CLS(P1, attr=P2)
збігається, лише якщо відбувається таке:
isinstance( <subject> , CLS)
перетворити
P1
на шаблон ключового слова за допомогоюCLS.__match_args__
Для кожного аргументу ключового слова
attr=P2
:hasattr( <subject> , "attr")
P2
відповідає<subject> .attr
… і так далі для відповідної пари ключового слова аргумент/шаблон.
8.7. Визначення функцій¶
Визначення функції визначає об’єкт функції, визначений користувачем (див. розділ Стандартна ієрархія типів):
funcdef ::= [decorators
] "def"funcname
[type_params
] "(" [parameter_list
] ")" ["->"expression
] ":"suite
decorators ::=decorator
+ decorator ::= "@"assignment_expression
NEWLINE parameter_list ::=defparameter
(","defparameter
)* "," "/" ["," [parameter_list_no_posonly
]] |parameter_list_no_posonly
parameter_list_no_posonly ::=defparameter
(","defparameter
)* ["," [parameter_list_starargs
]] |parameter_list_starargs
parameter_list_starargs ::= "*" [star_parameter
] (","defparameter
)* ["," ["**"parameter
[","]]] | "**"parameter
[","] parameter ::=identifier
[":"expression
] star_parameter ::=identifier
[":" ["*"]expression
] defparameter ::=parameter
["="expression
] funcname ::=identifier
Визначення функції - це виконуваний оператор. Його виконання прив’язує назву функції в поточному локальному просторі імен до об’єкта функції (обгортка навколо виконуваного коду для функції). Цей об’єкт функції містить посилання на поточний глобальний простір імен як глобальний простір імен, який буде використано під час виклику функції.
Визначення функції не виконує тіло функції; це виконується лише під час виклику функції. [4]
Визначення функції може бути обгорнуте одним або кількома виразами decorator. Вирази декоратора обчислюються, коли функція визначена в області видимості, яка містить визначення функції. Результат має бути викликаним, який викликається з об’єктом функції як єдиним аргументом. Повернене значення прив’язується до імені функції замість об’єкта функції. Кілька декораторів застосовуються вкладеним способом. Наприклад, такий код:
@f1(arg)
@f2
def func(): pass
приблизно еквівалентно
def func(): pass
func = f1(arg)(f2(func))
за винятком того, що вихідна функція тимчасово не прив’язана до імені func
.
Змінено в версії 3.9: Функції можуть бути прикрашені будь-яким дійсним assignment_expression
. Раніше граматика була набагато більш обмежувальною; подробиці див. PEP 614.
A list of type parameters may be given in square brackets
between the function’s name and the opening parenthesis for its parameter list.
This indicates to static type checkers that the function is generic. At runtime,
the type parameters can be retrieved from the function’s
__type_params__
attribute. See Generic functions for more.
Змінено в версії 3.12: Type parameter lists are new in Python 3.12.
Коли один або більше параметрів мають форму параметр =
вираз, кажуть, що функція має «значення параметрів за замовчуванням». Для параметра зі значенням за замовчуванням відповідний argument може бути пропущений у виклику, у цьому випадку значення параметра за замовчуванням замінюється. Якщо параметр має значення за замовчуванням, усі наступні параметри до «*
» також повинні мати значення за замовчуванням — це синтаксичне обмеження, яке не виражається граматикою.
Значення параметрів за замовчуванням обчислюються зліва направо, коли виконується визначення функції. Це означає, що вираз обчислюється один раз, коли визначається функція, і що те саме «попередньо обчислене» значення використовується для кожного виклику . Це особливо важливо розуміти, коли значення параметра за замовчуванням є змінним об’єктом, таким як список або словник: якщо функція змінює об’єкт (наприклад, шляхом додавання елемента до списку), значення параметра за замовчуванням фактично змінюється. Загалом це не те, що передбачалося. Щоб обійти це, використайте None
за умовчанням і явним чином перевірте його в тілі функції, наприклад:
def whats_on_the_telly(penguin=None):
if penguin is None:
penguin = []
penguin.append("property of the zoo")
return penguin
Більш детально семантика виклику функції описана в розділі Дзвінки. Виклик функції завжди призначає значення всім параметрам, згаданим у списку параметрів, або з позиційних аргументів, з ключових аргументів, або зі значень за замовчуванням. Якщо присутня форма «*identifier
», вона ініціалізується кортежем, що отримує будь-які надлишкові позиційні параметри, за умовчанням порожній кортеж. Якщо присутня форма «*identifier
», вона ініціалізується новим упорядкованим відображенням, отримуючи будь-які надлишкові аргументи ключового слова, за умовчанням до нового порожнього відображення того самого типу. Параметри після «*
» або «*identifier
» є параметрами лише для ключових слів і можуть передаватися лише аргументами ключових слів. Параметри перед «/
» є лише позиційними параметрами і можуть передаватися лише позиційними аргументами.
Змінено в версії 3.8: Синтаксис параметра функції /
може використовуватися для позначення лише позиційних параметрів. Подробиці див. PEP 570.
Parameters may have an annotation of the form «: expression
»
following the parameter name. Any parameter may have an annotation, even those of the form
*identifier
or **identifier
. (As a special case, parameters of the form
*identifier
may have an annotation «: *expression
».) Functions may have «return» annotation of
the form «-> expression
» after the parameter list. These annotations can be
any valid Python expression. The presence of annotations does not change the
semantics of a function. The annotation values are available as values of
a dictionary keyed by the parameters“ names in the __annotations__
attribute of the function object. If the annotations
import from
__future__
is used, annotations are preserved as strings at runtime which
enables postponed evaluation. Otherwise, they are evaluated when the function
definition is executed. In this case annotations may be evaluated in
a different order than they appear in the source code.
Змінено в версії 3.11: Parameters of the form «*identifier
» may have an annotation
«: *expression
». See PEP 646.
Також можна створювати анонімні функції (функції, не прив’язані до імені) для негайного використання у виразах. Тут використовуються лямбда-вирази, описані в розділі Лямбда. Зауважте, що лямбда-вираз — це лише скорочення спрощеного визначення функції; функція, визначена в операторі «def
», може бути передана або присвоєна іншому імені так само, як функція, визначена лямбда-виразом. Форма «def
» насправді є потужнішою, оскільки вона дозволяє виконувати кілька операторів і анотацій.
Примітка програміста: Функції є об’єктами першого класу. Оператор «def
», який виконується всередині визначення функції, визначає локальну функцію, яку можна повертати або передавати. Вільні змінні, які використовуються у вкладеній функції, можуть отримати доступ до локальних змінних функції, що містить def. Перегляньте розділ Називання та зв’язування для деталей.
Дивись також
- PEP 3107 - Анотації функцій
Оригінальна специфікація для анотацій функцій.
- PEP 484 - підказки типу
Визначення стандартного значення для анотацій: тип підказок.
- PEP 526 - Синтаксис для анотацій змінних
Ability to type hint variable declarations, including class variables and instance variables.
- PEP 563 - Відкладена оцінка анотацій
Підтримка прямих посилань в анотаціях завдяки збереженню анотацій у формі рядка під час виконання замість нетерплячої оцінки.
- PEP 318 - Decorators for Functions and Methods
Function and method decorators were introduced. Class decorators were introduced in PEP 3129.
8.8. Визначення класів¶
Визначення класу визначає об’єкт класу (див. розділ Стандартна ієрархія типів):
classdef ::= [decorators
] "class"classname
[type_params
] [inheritance
] ":"suite
inheritance ::= "(" [argument_list
] ")" classname ::=identifier
Визначення класу є виконуваним оператором. Список успадкування зазвичай надає список базових класів (див. Метакласи для більш просунутого використання), тому кожен елемент у списку повинен оцінюватися як об’єкт класу, який дозволяє створювати підкласи. Класи без списку успадкування успадковують, за замовчуванням, від базового класу object
; отже,
class Foo:
pass
еквівалентно
class Foo(object):
pass
Потім набір класів виконується в новому фреймі виконання (див. Називання та зв’язування), використовуючи щойно створений локальний простір імен і оригінальний глобальний простір імен. (Зазвичай набір містить в основному визначення функцій.) Коли набір класу завершує виконання, його кадр виконання відкидається, але його локальний простір імен зберігається. [5] Потім створюється об’єкт класу з використанням списку успадкування для базових класів і збереженого локального простору імен для словника атрибутів. Ім’я класу прив’язане до цього об’єкта класу в оригінальному локальному просторі імен.
The order in which attributes are defined in the class body is preserved
in the new class’s __dict__
. Note that this is reliable only right
after the class is created and only for classes that were defined using
the definition syntax.
Створення класів можна значно налаштувати за допомогою metaclasses.
Класи також можна декорувати: як і при декоруванні функцій,
@f1(arg)
@f2
class Foo: pass
приблизно еквівалентно
class Foo: pass
Foo = f1(arg)(f2(Foo))
Правила оцінки для виразів декоратора такі ж, як і для декораторів функцій. Потім результат прив’язується до імені класу.
Змінено в версії 3.9: Класи можуть бути прикрашені будь-яким дійсним assignment_expression
. Раніше граматика була набагато більш обмежувальною; подробиці див. PEP 614.
A list of type parameters may be given in square brackets
immediately after the class’s name.
This indicates to static type checkers that the class is generic. At runtime,
the type parameters can be retrieved from the class’s
__type_params__
attribute. See Generic classes for more.
Змінено в версії 3.12: Type parameter lists are new in Python 3.12.
Примітка програміста: Змінні, визначені у визначенні класу, є атрибутами класу; їх ділять інстанції. Атрибути екземпляра можна встановити в методі за допомогою self.name = value
. Як атрибути класу, так і атрибути екземпляра доступні через нотацію «self.name
», а атрибут екземпляра приховує атрибут класу з таким самим іменем, коли до нього звертаються таким чином. Атрибути класу можна використовувати як значення за замовчуванням для атрибутів екземплярів, але використання там змінних значень може призвести до неочікуваних результатів. Дескриптори можна використовувати для створення змінних екземпляра з різними деталями реалізації.
8.9. Співпрограми¶
Added in version 3.5.
8.9.1. Визначення функції співпрограми¶
async_funcdef ::= [decorators
] "async" "def"funcname
"(" [parameter_list
] ")" ["->"expression
] ":"suite
Виконання співпрограм Python можна призупинити та відновити в багатьох точках (див. coroutine). Вирази await
, async for
і async with
можна використовувати лише в тілі функції співпрограми.
Функції, визначені за допомогою синтаксису async def
, завжди є функціями співпрограми, навіть якщо вони не містять ключових слів await
або async
.
Використання виразу yield from
всередині тіла функції співпрограми є SyntaxError
.
Приклад функції співпрограми:
async def func(param1, param2):
do_stuff()
await some_coroutine()
Змінено в версії 3.7: await
і async
тепер є ключовими словами; раніше вони розглядалися як такі лише всередині тіла співпрограми.
8.9.2. Оператор async for
¶
async_for_stmt ::= "async" for_stmt
asynchronous iterable надає метод __aiter__
, який безпосередньо повертає asynchronous iterator, який може викликати асинхронний код у своєму методі __anext__
.
Оператор async for
дозволяє зручно виконувати ітерації над асинхронними ітераціями.
Наступний код:
async for TARGET in ITER:
SUITE
else:
SUITE2
Семантично еквівалентний:
iter = (ITER)
iter = type(iter).__aiter__(iter)
running = True
while running:
try:
TARGET = await type(iter).__anext__(iter)
except StopAsyncIteration:
running = False
else:
SUITE
else:
SUITE2
See also __aiter__()
and __anext__()
for details.
Це SyntaxError
, якщо використовувати оператор async for
поза тілом функції співпрограми.
8.9.3. Оператор async with
¶
async_with_stmt ::= "async" with_stmt
Асинхронний менеджер контексту (asynchronous context manager) — це менеджер контексту (context manager),який може призупинити виконання своїх методів enter і exit.
Наступний код:
async with EXPRESSION as TARGET:
SUITE
семантично еквівалентний:
manager = (EXPRESSION)
aenter = type(manager).__aenter__
aexit = type(manager).__aexit__
value = await aenter(manager)
hit_except = False
try:
TARGET = value
SUITE
except:
hit_except = True
if not await aexit(manager, *sys.exc_info()):
raise
finally:
if not hit_except:
await aexit(manager, None, None, None)
See also __aenter__()
and __aexit__()
for details.
Це SyntaxError
, якщо використовувати оператор async with
поза тілом функції співпрограми.
Дивись також
- PEP 492 - Співпрограми з синтаксисом async і await
Пропозиція, яка зробила співпрограми справжньою автономною концепцією в Python і додала допоміжний синтаксис.
8.10. Type parameter lists¶
Added in version 3.12.
type_params ::= "["type_param
(","type_param
)* "]" type_param ::=typevar
|typevartuple
|paramspec
typevar ::=identifier
(":"expression
)? typevartuple ::= "*"identifier
paramspec ::= "**"identifier
Functions (including coroutines), classes and type aliases may contain a type parameter list:
def max[T](args: list[T]) -> T:
...
async def amax[T](args: list[T]) -> T:
...
class Bag[T]:
def __iter__(self) -> Iterator[T]:
...
def add(self, arg: T) -> None:
...
type ListOrSet[T] = list[T] | set[T]
Semantically, this indicates that the function, class, or type alias is generic over a type variable. This information is primarily used by static type checkers, and at runtime, generic objects behave much like their non-generic counterparts.
Type parameters are declared in square brackets ([]
) immediately
after the name of the function, class, or type alias. The type parameters
are accessible within the scope of the generic object, but not elsewhere.
Thus, after a declaration def func[T](): pass
, the name T
is not available in
the module scope. Below, the semantics of generic objects are described
with more precision. The scope of type parameters is modeled with a special
function (technically, an annotation scope) that
wraps the creation of the generic object.
Generic functions, classes, and type aliases have a
__type_params__
attribute listing their type parameters.
Type parameters come in three kinds:
typing.TypeVar
, introduced by a plain name (e.g.,T
). Semantically, this represents a single type to a type checker.typing.TypeVarTuple
, introduced by a name prefixed with a single asterisk (e.g.,*Ts
). Semantically, this stands for a tuple of any number of types.typing.ParamSpec
, introduced by a name prefixed with two asterisks (e.g.,**P
). Semantically, this stands for the parameters of a callable.
typing.TypeVar
declarations can define bounds and constraints with
a colon (:
) followed by an expression. A single expression after the colon
indicates a bound (e.g. T: int
). Semantically, this means
that the typing.TypeVar
can only represent types that are a subtype of
this bound. A parenthesized tuple of expressions after the colon indicates a
set of constraints (e.g. T: (str, bytes)
). Each member of the tuple should be a
type (again, this is not enforced at runtime). Constrained type variables can only
take on one of the types in the list of constraints.
For typing.TypeVar
s declared using the type parameter list syntax,
the bound and constraints are not evaluated when the generic object is created,
but only when the value is explicitly accessed through the attributes __bound__
and __constraints__
. To accomplish this, the bounds or constraints are
evaluated in a separate annotation scope.
typing.TypeVarTuple
s and typing.ParamSpec
s cannot have bounds
or constraints.
The following example indicates the full set of allowed type parameter declarations:
def overly_generic[
SimpleTypeVar,
TypeVarWithBound: int,
TypeVarWithConstraints: (str, bytes),
*SimpleTypeVarTuple,
**SimpleParamSpec,
](
a: SimpleTypeVar,
b: TypeVarWithBound,
c: Callable[SimpleParamSpec, TypeVarWithConstraints],
*d: SimpleTypeVarTuple,
): ...
8.10.1. Generic functions¶
Generic functions are declared as follows:
def func[T](arg: T): ...
This syntax is equivalent to:
annotation-def TYPE_PARAMS_OF_func():
T = typing.TypeVar("T")
def func(arg: T): ...
func.__type_params__ = (T,)
return func
func = TYPE_PARAMS_OF_func()
Here annotation-def
indicates an annotation scope,
which is not actually bound to any name at runtime. (One
other liberty is taken in the translation: the syntax does not go through
attribute access on the typing
module, but creates an instance of
typing.TypeVar
directly.)
The annotations of generic functions are evaluated within the annotation scope used for declaring the type parameters, but the function’s defaults and decorators are not.
The following example illustrates the scoping rules for these cases, as well as for additional flavors of type parameters:
@decorator
def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = some_default):
...
Except for the lazy evaluation of the
TypeVar
bound, this is equivalent to:
DEFAULT_OF_arg = some_default
annotation-def TYPE_PARAMS_OF_func():
annotation-def BOUND_OF_T():
return int
# In reality, BOUND_OF_T() is evaluated only on demand.
T = typing.TypeVar("T", bound=BOUND_OF_T())
Ts = typing.TypeVarTuple("Ts")
P = typing.ParamSpec("P")
def func(*args: *Ts, arg: Callable[P, T] = DEFAULT_OF_arg):
...
func.__type_params__ = (T, Ts, P)
return func
func = decorator(TYPE_PARAMS_OF_func())
The capitalized names like DEFAULT_OF_arg
are not actually
bound at runtime.
8.10.2. Generic classes¶
Generic classes are declared as follows:
class Bag[T]: ...
This syntax is equivalent to:
annotation-def TYPE_PARAMS_OF_Bag():
T = typing.TypeVar("T")
class Bag(typing.Generic[T]):
__type_params__ = (T,)
...
return Bag
Bag = TYPE_PARAMS_OF_Bag()
Here again annotation-def
(not a real keyword) indicates an
annotation scope, and the name
TYPE_PARAMS_OF_Bag
is not actually bound at runtime.
Generic classes implicitly inherit from typing.Generic
.
The base classes and keyword arguments of generic classes are
evaluated within the type scope for the type parameters,
and decorators are evaluated outside that scope. This is illustrated
by this example:
@decorator
class Bag(Base[T], arg=T): ...
Це еквівалентно:
annotation-def TYPE_PARAMS_OF_Bag():
T = typing.TypeVar("T")
class Bag(Base[T], typing.Generic[T], arg=T):
__type_params__ = (T,)
...
return Bag
Bag = decorator(TYPE_PARAMS_OF_Bag())
8.10.3. Generic type aliases¶
The type
statement can also be used to create a generic type alias:
type ListOrSet[T] = list[T] | set[T]
Except for the lazy evaluation of the value, this is equivalent to:
annotation-def TYPE_PARAMS_OF_ListOrSet():
T = typing.TypeVar("T")
annotation-def VALUE_OF_ListOrSet():
return list[T] | set[T]
# In reality, the value is lazily evaluated
return typing.TypeAliasType("ListOrSet", VALUE_OF_ListOrSet(), type_params=(T,))
ListOrSet = TYPE_PARAMS_OF_ListOrSet()
Here, annotation-def
(not a real keyword) indicates an
annotation scope. The capitalized names
like TYPE_PARAMS_OF_ListOrSet
are not actually bound at runtime.
Виноски