8. Sentencias compuestas¶
Las sentencias compuestas contienen (grupos de) otras sentencias; estas afectan o controlan la ejecución de esas otras sentencias de alguna manera. En general, las sentencias compuestas abarcan varias líneas, aunque en representaciones simples una sentencia compuesta completa puede estar contenida en una línea.
Las sentencias if
, while
y for
implementan construcciones de control de flujo tradicionales. try
especifica gestores de excepción o código de limpieza para un grupo de sentencias, mientras que las sentencias with
permite la ejecución del código de inicialización y finalización alrededor de un bloque de código. Las definiciones de función y clase también son sentencias sintácticamente compuestas.
Una sentencia compuesta consta de una o más “cláusulas”. Una cláusula consta de un encabezado y una “suite”. Los encabezados de cláusula de una declaración compuesta particular están todos en el mismo nivel de indentación. Cada encabezado de cláusula comienza con una palabra clave de identificación única y termina con dos puntos. Una suite es un grupo de sentencias controladas por una cláusula. Una suite puede ser una o más sentencias simples separadas por punto y coma en la misma línea como el encabezado, siguiendo los dos puntos del encabezado, o puede ser una o puede ser una o más declaraciones indentadas en líneas posteriores. Solo la última forma de una suite puede contener sentencias compuestas anidadas; lo siguiente es ilegal, principalmente porque no estaría claro a qué cláusula if
seguido de la cláusula else
hace referencia:
if test1: if test2: print(x)
También tenga en cuenta que el punto y coma se une más apretado que los dos puntos en este contexto, de modo que en el siguiente ejemplo, todas o ninguna de las llamadas print()
se ejecutan:
if x < y < z: print(x); print(y); print(z)
Resumiendo:
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
)* [";"]
Tenga en cuenta que las sentencias siempre terminan en un NEWLINE
posiblemente seguida de DEDENT
. También tenga en cuenta que las cláusulas de continuación opcionales siempre comienzan con una palabra clave que no puede iniciar una sentencia, por lo tanto, no hay ambigüedades (el problema de “colgado if
” se resuelve en Python al requerir que las sentencias anidadas if
deben estar indentadas).
El formato de las reglas gramaticales en las siguientes secciones coloca cada cláusula en una línea separada para mayor claridad.
8.1. La sentencia if
¶
La sentencia if
se usa para la ejecución condicional:
if_stmt ::= "if"assignment_expression
":"suite
("elif"assignment_expression
":"suite
)* ["else" ":"suite
]
Selecciona exactamente una de las suites evaluando las expresiones una por una hasta que se encuentre una verdadera (vea la sección Operaciones booleanas para la definición de verdadero y falso); entonces esa suite se ejecuta (y ninguna otra parte de la sentencia if
se ejecuta o evalúa). Si todas las expresiones son falsas, se ejecuta la suite de cláusulas else
, si está presente.
8.2. La sentencia while
¶
La sentencia while
se usa para la ejecución repetida siempre que una expresión sea verdadera:
while_stmt ::= "while"assignment_expression
":"suite
["else" ":"suite
]
Esto prueba repetidamente la expresión y, si es verdadera, ejecuta la primera suite; si la expresión es falsa (que puede ser la primera vez que se prueba), se ejecuta el conjunto de cláusulas else
, si está presente, y el bucle termina.
La sentencia break
ejecutada en la primer suite termina el bucle sin ejecutar la suite de cláusulas else
. La sentencia continue
ejecutada en la primera suite omite el resto de la suite y vuelve a probar la expresión.
8.3. La sentencia for
¶
La sentencia for
se usa para iterar sobre los elementos de una secuencia (como una cadena de caracteres, tupla o lista) u otro objeto iterable:
for_stmt ::= "for"target_list
"in"starred_list
":"suite
["else" ":"suite
]
La expresión starred_list
se evalúa una vez; debería producir un objeto iterable. Se crea un iterator para ese iterable. A continuación, el primer elemento proporcionado por el iterador se asigna a la lista de destino utilizando las reglas estándar para las asignaciones (consulte Declaraciones de asignación) y se ejecuta la suite. Esto se repite para cada elemento proporcionado por el iterador. Cuando se agota el iterador, se ejecuta el conjunto de la cláusula else
, si está presente, y el ciclo termina.
La sentencia break
ejecutada en la primera suite termina el bucle sin ejecutar el conjunto de cláusulas else
. La sentencia continue
ejecutada en la primera suite omite el resto de las cláusulas y continúa con el siguiente elemento, o con la cláusula else
si no hay un elemento siguiente.
El bucle for
realiza asignaciones a las variables en la lista. Esto sobrescribe todas las asignaciones anteriores a esas variables, incluidas las realizadas en la suite del bucle 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.
Distinto en la versión 3.11: Los elementos destacados ahora están permitidos en la lista de expresiones.
8.4. La sentencia try
¶
La sentencia try
especifica controladores de excepciones y/o código de limpieza para un grupo de sentencias:
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
Se puede encontrar información adicional sobre las excepciones en la sección Excepciones, e información sobre el uso de la sentencia raise
, para lanzar excepciones se puede encontrar en la sección La declaración raise.
8.4.1. Cláusula except
¶
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.
Si ninguna cláusula except
coincide con la excepción, la búsqueda de un controlador de excepciones continúa en el código circundante y en la pila de invocaciones. [1]
Si la evaluación de una expresión en el encabezado de una cláusula except
genera una excepción, la búsqueda original de un controlador se cancela y comienza una búsqueda de la nueva excepción en el código circundante y en la pila de llamadas (se trata como si toda la sentencia try
generara la excepción).
Cuando se encuentra una cláusula except
coincidente, la excepción se asigna al destino especificado después de la palabra clave as
en esa cláusula except
, si está presente, y se ejecuta el conjunto de la cláusula except
. Todas las cláusulas except
deben tener un bloque ejecutable. Cuando se alcanza el final de este bloque, la ejecución continúa normalmente después de la instrucción try
completa. (Esto significa que si existen dos controladores anidados para la misma excepción y la excepción se produce en la cláusula try
del controlador interno, el controlador externo no controlará la excepción).
Cuando se ha asignado una excepción mediante as target
, se borra al final de la cláusula except
. Esto es como si
except E as N:
foo
fue traducido a
except E as N:
try:
foo
finally:
del N
Esto significa que la excepción debe asignarse a un nombre diferente para poder hacer referencia a ella después de la cláusula except
. Las excepciones se borran porque con el rastreo adjunto, forman un ciclo de referencia con el marco de la pila, manteniendo todos los locales en ese marco vivos hasta que ocurra la próxima recolección de elementos no utilizados.
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. Cláusula except*
¶
La(s) cláusula(s) except*
se utilizan para manejar ExceptionGroup
s. El tipo de excepción para la coincidencia se interpreta como en el caso de except
, pero en el caso de los grupos de excepción podemos tener coincidencias parciales cuando el tipo coincide con algunas de las excepciones del grupo. Esto significa que se pueden ejecutar varias cláusulas except*
, cada una de las cuales maneja parte del grupo de excepciones. Cada cláusula se ejecuta como máximo una vez y maneja un grupo de excepciones de todas las excepciones coincidentes. Cada excepción en el grupo es manejada por una cláusula except*
como máximo, la primera que coincida.
>>> 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.
Si la excepción generada no es un grupo de excepciones y su tipo coincide con una de las cláusulas except*
, un grupo de excepciones la captura y la encapsula con una cadena de mensaje vacía.
>>> 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. La sentencia else
¶
La cláusula opcional else
se ejecuta si el flujo de control sale de la suite try
, no se produjo ninguna excepción, y no se ejecutó la sentencia return
, continue
o break
. Las excepciones en la cláusula else
no se gestionaron con las cláusulas precedentes except
.
8.4.4. Cláusula finally
¶
Si finally
está presente, especifica un controlador de “limpieza”. Se ejecuta la cláusula try
, incluidas las cláusulas except
y else
. Si ocurre una excepción en cualquiera de las cláusulas y no se maneja, la excepción se guarda temporalmente. Se ejecuta la cláusula finally
. Si hay una excepción guardada, se vuelve a generar al final de la cláusula finally
. Si la cláusula finally
genera otra excepción, la excepción guardada se establece como el contexto de la nueva excepción. Si la cláusula finally
ejecuta una sentencia return
, break
o continue
, la excepción guardada se descarta:
>>> def f():
... try:
... 1/0
... finally:
... return 42
...
>>> f()
42
La información de excepción no está disponible para el programa durante la ejecución de la cláusula finally
.
Cuando se ejecuta una sentencia return
, break
o continue
en el conjunto try
de una sentencia try
…finally
, la cláusula finally
también se ejecuta “al salir”.
El valor de retorno de una función está determinado por la última instrucción return
ejecutada. Dado que la cláusula finally
siempre se ejecuta, una sentencia return
ejecutada en la cláusula finally
siempre será la última en ejecutarse:
>>> def foo():
... try:
... return 'try'
... finally:
... return 'finally'
...
>>> foo()
'finally'
Distinto en la versión 3.8: Antes de Python 3.8, una declaración continue
era ilegal en la cláusula finally
debido a un problema con la implementación.
8.5. La sentencia with
¶
La sentencia with
se usa para ajustar la ejecución de un bloque con métodos definidos por un administrador de contexto (ver sección Gestores de Contexto en la Declaración with). Esto permite que los patrones de uso comunes try
…except
…finally
se encapsulen para una reutilización conveniente.
with_stmt ::= "with" ( "("with_stmt_contents
","? ")" |with_stmt_contents
) ":"suite
with_stmt_contents ::=with_item
(","with_item
)* with_item ::=expression
["as"target
]
La ejecución de la sentencia with
con un «item» se realiza de la siguiente manera:
La expresión de contexto (la expresión dada en
with_item
) se evalúa para obtener un administrador de contexto.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.Nota
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.La suite se ejecuta.
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.
El siguiente código:
with EXPRESSION as TARGET:
SUITE
es semánticamente equivalente a:
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)
Con más de un elemento, los administradores de contexto se procesan como si varias sentencias with
estuvieran anidadas:
with A() as a, B() as b:
SUITE
es semánticamente equivalente a:
with A() as a:
with B() as b:
SUITE
También puedes escribir administradores de contexto de múltiples ítems en múltiples lineas si los ítems están entre paréntesis. Por ejemplo:
with (
A() as a,
B() as b,
):
SUITE
Distinto en la versión 3.1: Soporte para múltiples expresiones de contexto.
Distinto en la versión 3.10: Soporte para el uso de paréntesis de agrupación para separar la declaración en múltiples líneas.
8.6. La sentencia match
¶
Added in version 3.10.
La declaración match es usada para coincidencia de patrones. Sintaxis:
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
Nota
Esta sección utiliza comillas simples para denotar las palabras clave suaves.
La coincidencia de patrones toma un patrón como entrada (delante de case
) y un valor de búsqueda (delante de match
). El patrón (que puede contener subpatrones) es comparado con el valor de búsqueda. Los resultados son:
Una coincidencia exitosa o fallida (también llamada éxito o fracaso de un patrón).
Una posible vinculación de los valores coincidentes con un nombre. Los requisitos previos para esto se discuten abajo.
Las palabras clave match
y case
son palabras clave suaves.
Ver también
8.6.1. Resumen¶
A continuación, un resumen del flujo lógico de una declaración de coincidencia:
Se evalúa la expresión
subject_expr
y se obtiene un valor sujeto resultante. Si la expresión contiene una coma, se construye una tupla utilizando las reglas estándar.Se intenta coincidir cada patrón en un
case_block
con el valor sujeto. Las reglas específicas para el éxito o el fracaso se describen abajo. El intento de coincidencia también puede enlazar algunos o todos los nombres independientes dentro del patrón. Las reglas precisas de enlace de patrones varían según el tipo de patrón y se especifican a continuación. Los enlaces de nombre realizados durante una coincidencia de patrones exitosa sobreviven al bloque ejecutado y se pueden usar después de la declaración de coincidencia.Nota
Durante las coincidencias de patrones fallidas, algunos subpatrones pueden tener éxito. No confíe en que los enlaces se realicen para una coincidencia fallida. Por el contrario, no confíe en que las variables permanezcan sin cambios después de una coincidencia fallida. El comportamiento exacto depende de la implementación y puede variar. Esta es una decisión intencional para permitir que diferentes implementaciones añadan optimizaciones.
Si el patrón es exitoso, se evalúa la protección correspondiente (si está presente). En este caso se garantiza que todos los enlaces de nombres han ocurrido.
Si la protección se evalúa como verdadera o no existe, se ejecuta el
block
dentro decase_block
.En caso contrario, se intenta con el siguiente
case_block
como se ha descrito anteriormente.Si no hay más bloques de casos, la declaración de coincidencia se completa.
Nota
Por lo general, los usuarios no deben confiar en que se evalúe un patrón. Dependiendo de la implementación, el intérprete puede almacenar en caché los valores o utilizar otras optimizaciones que omitan las evaluaciones repetidas.
Un ejemplo de declaración de coincidencia:
>>> 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
En este caso, if flag
es una protección. Lea más sobre eso en la siguiente sección.
8.6.2. Protecciones¶
guard ::= "if" named_expression
Una guard
(que es parte del case
) debe ser exitosa para que el código dentro de case
sea ejecutado. Toma la forma: if
seguida de una expresión.
El flujo lógico de un bloque case
con una guard
es el siguiente:
Se comprueba que el patrón del bloque
case
fue exitoso. Si el patrón falló, elguard
no se evalúa y se comprueba el siguiente bloquecase
.Si el patrón tuvo éxito, se evalúa el
guard
.Si la condición del
guard
es verdadera, se selecciona el bloque de ese caso.Si la condición del
guard
es falsa, el bloque de ese caso no es seleccionado.Si el
guard
lanza una excepción durante la evaluación, se levanta la excepción.
Se permite que las protecciones tengan efectos secundarios, ya que son expresiones. La evaluación de la protección debe ir desde el primer al último bloque de casos, uno a la vez, saltando los bloques de casos cuyo(s) patrón(es) no tenga(n) éxito. (Es decir, la evaluación de las protecciones debe realizarse en orden.) La evaluación de las protecciones debe detenerse una vez que se selecciona un bloque de casos.
8.6.3. Bloques de Casos Irrefutables¶
Un bloque de casos irrefutable es un bloque de casos que coincide con todo. Una declaración de coincidencia puede tener como máximo un bloque de casos irrefutable, y debe ser el último.
Un bloque de casos se considera irrefutable si no tiene protección y su patrón es irrefutable. Un patrón se considera irrefutable si podemos demostrar, sólo por su sintaxis, que siempre tendrá éxito. Sólo los siguientes patrones son irrefutables:
patrones AS cuyo lado izquierdo es irrefutable
Patrones OR que contienen al menos un patrón irrefutable
patrones irrefutables entre paréntesis
8.6.4. Patrones¶
Nota
Esta sección utiliza notaciones gramaticales más allá del estándar EBNF:
la notación
SEP.RULE+
es la abreviación deRULE (SEP RULE)*
la notación
!RULE
es la abreviación de una aserción de anticipación negativa
La sintaxis de nivel superior para patrones
es:
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
Las descripciones a continuación incluirán una descripción «en términos simples» de lo que hace un patrón con fines ilustrativos (créditos a Raymond Hettinger por un documento que inspiró la mayoría de las descripciones). Tenga en cuenta que estas descripciones tienen únicamente fines ilustrativos y que may not refleja la implementación subyacente. Además, no cubren todos los formularios válidos.
8.6.4.1. Patrones OR¶
Un patrón OR son dos o más patrones separados por barras verticales |
. Sintaxis:
or_pattern ::= "|".closed_pattern
+
Solo el subpatrón final puede ser irrefutable, y cada subpatrón debe vincular el mismo conjunto de nombres para evitar ambigüedades.
Un patrón OR hace coincidir cada uno de sus subpatrones a su vez con el valor del sujeto, hasta que uno tiene éxito. Entonces, el patrón OR se considera exitoso. De lo contrario, si ninguno de los subpatrones tiene éxito, el patrón OR falla.
En términos simples, P1 | P2 | ...
intentará igualar P1
, si falla, intentará igualar P2
, teniendo éxito inmediatamente si alguno tiene éxito, fallando en caso contrario.
8.6.4.2. patrones AS¶
Un patrón AS coincide con un patrón OR a la izquierda de la palabra clave as
con un sujeto. Sintaxis:
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 _
.
En términos simples, P as NAME
coincidirá con P
y, en caso de éxito, establecerá NAME = <subject>
.
8.6.4.3. Patrones literales¶
Un patrón literal corresponde a la mayoría de literals en Python. Sintaxis:
literal_pattern ::=signed_number
|signed_number
"+" NUMBER |signed_number
"-" NUMBER |strings
| "None" | "True" | "False" signed_number ::= ["-"] NUMBER
La regla strings
y el token NUMBER
se definen en standard Python grammar. Se admiten cadenas entre comillas triples. Se admiten cadenas sin formato y cadenas de bytes. f-strings no es compatible.
Los formularios signed_number '+' NUMBER
y signed_number '-' NUMBER
son para expresar complex numbers; requieren un número real a la izquierda y un número imaginario a la derecha. P.ej. 3 + 4j
.
En términos simples, LITERAL
solo tendrá éxito si <subject> == LITERAL
. Para los singleton None
, True
y False
, se utiliza el operador is
.
8.6.4.4. Patrones de captura¶
Un patrón de captura vincula el valor del sujeto a un nombre. Sintaxis:
capture_pattern ::= !'_' NAME
Un solo guión bajo _
no es un patrón de captura (esto es lo que expresa !'_'
). En su lugar, se trata como un wildcard_pattern
.
En un patrón dado, un nombre dado solo se puede vincular una vez. P.ej. case x, x: ...
no es válido mientras case [x] | x: ...
está permitido.
Los patrones de captura siempre tienen éxito. El enlace sigue las reglas de alcance establecidas por el operador de expresión de asignación en PEP 572; el nombre se convierte en una variable local en el alcance de la función contenedora más cercana, a menos que haya una declaración global
o nonlocal
aplicable.
En términos simples, NAME
siempre tendrá éxito y establecerá NAME = <subject>
.
8.6.4.5. Patrones comodín¶
Un patrón comodín siempre tiene éxito (coincide con cualquier cosa) y no vincula ningún nombre. Sintaxis:
wildcard_pattern ::= '_'
_
es un soft keyword dentro de cualquier patrón, pero solo dentro de patrones. Es un identificador, como de costumbre, incluso dentro de las expresiones de sujeto match
, guard
sy bloques case
.
En términos simples, _
siempre tendrá éxito.
8.6.4.6. Patrones de valor¶
Un patrón de valor representa un valor con nombre en Python. Sintaxis:
value_pattern ::=attr
attr ::=name_or_attr
"." NAME name_or_attr ::=attr
| NAME
El nombre con puntos en el patrón se busca usando el estándar Python name resolution rules. El patrón tiene éxito si el valor encontrado se compara con el valor del sujeto (usando el operador de igualdad ==
).
En términos simples, NAME1.NAME2
solo tendrá éxito si <subject> == NAME1.NAME2
Nota
Si el mismo valor ocurre varias veces en la misma declaración de coincidencia, el intérprete puede almacenar en caché el primer valor encontrado y reutilizarlo en lugar de repetir la misma búsqueda. Este caché está estrictamente vinculado a una ejecución determinada de una declaración de coincidencia determinada.
8.6.4.7. Patrones de grupo¶
Un patrón de grupo permite a los usuarios agregar paréntesis alrededor de los patrones para enfatizar la agrupación deseada. De lo contrario, no tiene sintaxis adicional. Sintaxis:
group_pattern ::= "(" pattern
")"
En términos simples, (P)
tiene el mismo efecto que P
.
8.6.4.8. Patrones de secuencia¶
Un patrón de secuencia contiene varios subpatrones para hacer coincidir con elementos de secuencia. La sintaxis es similar al desempaquetado de una lista o tupla.
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
)
No hay diferencia si se utilizan paréntesis o corchetes para los patrones de secuencia (es decir, (...)
vs [...]
).
Nota
Un solo patrón encerrado entre paréntesis sin una coma final (por ejemplo, (3 | 4)
) es un group pattern. Mientras que un solo patrón encerrado entre corchetes (por ejemplo, [3 | 4]
) sigue siendo un patrón de secuencia.
A lo sumo, un subpatrón de estrella puede estar en un patrón de secuencia. El subpatrón de estrella puede ocurrir en cualquier posición. Si no hay ningún subpatrón de estrella, el patrón de secuencia es un patrón de secuencia de longitud fija; de lo contrario, es un patrón de secuencia de longitud variable.
El siguiente es el flujo lógico para hacer coincidir un patrón de secuencia con un valor de sujeto:
Si el valor del sujeto no es una secuencia [2], el patrón de secuencia falla.
Si el valor del sujeto es una instancia de
str
,bytes
obytearray
, el patrón de secuencia falla.Los pasos subsiguientes dependen de si el patrón de secuencia es de longitud fija o variable.
Si el patrón de secuencia es de longitud fija:
Si la longitud de la secuencia del sujeto no es igual al número de subpatrones, el patrón de secuencia falla
Los subpatrones del patrón de secuencia se hacen coincidir con sus elementos correspondientes en la secuencia del sujeto de izquierda a derecha. El emparejamiento se detiene tan pronto como falla un subpatrón. Si todos los subpatrones tienen éxito en hacer coincidir su elemento correspondiente, el patrón de secuencia tiene éxito.
De lo contrario, si el patrón de secuencia es de longitud variable:
Si la longitud de la secuencia del sujeto es menor que el número de subpatrones sin estrella, el patrón de secuencia falla.
Los subpatrones principales no en estrella se emparejan con sus elementos correspondientes como para las secuencias de longitud fija.
Si el paso anterior tiene éxito, el subpatrón en estrella coincide con una lista formada por los elementos restantes del sujeto, excluyendo los elementos restantes correspondientes a los subpatrones que no son en estrella que siguen el subpatrón en estrella.
Los subpatrones restantes que no son estrellas se emparejan con sus elementos temáticos correspondientes, como para una secuencia de longitud fija.
Nota
La longitud de la secuencia del sujeto se obtiene a través de
len()
(es decir, a través del protocolo__len__()
). El intérprete puede almacenar en caché esta longitud de manera similar a value patterns.
En términos simples, [P1, P2, P3,
… , P<N>]
solo coincide si ocurre todo lo siguiente:
comprobar que
<subject>
es una secuencialen(subject) == <N>
P1
coincide con<subject>[0]
(tenga en cuenta que esta coincidencia también puede vincular nombres)P2
coincide con<subject>[1]
(tenga en cuenta que esta coincidencia también puede vincular nombres)… y así sucesivamente para el patrón/elemento correspondiente.
8.6.4.9. Patrones de mapeo¶
Un patrón de asignación contiene uno o más patrones clave-valor. La sintaxis es similar a la construcción de un diccionario. Sintaxis:
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
Como máximo, un patrón de estrella doble puede estar en un patrón de mapeo. El patrón de estrella doble debe ser el último subpatrón del patrón de mapeo.
No se permiten claves duplicadas en patrones de mapeo. Las claves literales duplicadas lanzarán un SyntaxError
. Dos claves que de otro modo tendrían el mismo valor lanzarán un ValueError
en tiempo de ejecución.
El siguiente es el flujo lógico para hacer coincidir un patrón de mapeo con un valor de sujeto:
Si el valor del sujeto no es una asignación [3], el patrón de asignación falla.
Si cada clave dada en el patrón de mapeo está presente en el mapeo del sujeto, y el patrón para cada clave coincide con el elemento correspondiente del mapeo del sujeto, el patrón de mapeo tiene éxito.
Si se detectan claves duplicadas en el patrón de mapeo, el patrón se considera inválido. Se lanza un
SyntaxError
para valores literales duplicados; o unValueError
para claves con nombre del mismo valor.
Nota
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__()
.
En términos simples, {KEY1: P1, KEY2: P2, ... }
solo coincide si ocurre todo lo siguiente:
comprobar
<subject>
es un mapeoKEY1 in <subject>
P1
coincide con<subject>[KEY1]
… y así sucesivamente para el par correspondiente de KEY / patrón.
8.6.4.10. Patrones de clase¶
Un patrón de clase representa una clase y sus argumentos posicionales y de palabras clave (si los hay). Sintaxis:
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
La misma palabra clave no debe repetirse en los patrones de clase.
El siguiente es el flujo lógico para hacer coincidir un patrón de clase con un valor de materia:
Si
name_or_attr
no es una instancia deltype
incorporado, genereTypeError
.Si el valor del sujeto no es una instancia de
name_or_attr
(probado a través deisinstance()
), el patrón de clase falla.Si no hay argumentos de patrón, el patrón tiene éxito. De lo contrario, los pasos siguientes dependen de si están presentes patrones de argumentos de posición o de palabras clave.
Para varios tipos integrados (especificados a continuación), se acepta un único subpatrón posicional que coincidirá con todo el tema; para estos tipos, los patrones de palabras clave también funcionan como para otros tipos.
Si solo hay patrones de palabras clave, se procesan de la siguiente manera, uno por uno:
I. La palabra clave se busca como un atributo del tema.
Si esto lanza una excepción distinta de
AttributeError
, la excepción aparece.Si esto lanza
AttributeError
, el patrón de clase ha fallado.De lo contrario, el subpatrón asociado con el patrón de palabra clave se compara con el valor del atributo del sujeto. Si esto falla, el patrón de clase falla; si esto tiene éxito, la coincidencia continúa con la siguiente palabra clave.
II. Si todos los patrones de palabras clave tienen éxito, el patrón de clase tiene éxito.
Si hay algún patrón posicional presente, se convierte en patrones de palabras clave utilizando el atributo
__match_args__
en la clasename_or_attr
antes de hacer coincidir:I. Se llama el equivalente de
getattr(cls, "__match_args__", ())
.Si esto lanza una excepción, la excepción surge.
Si el valor retornado no es una tupla, la conversión falla y se lanza
TypeError
.Si hay más patrones posicionales que
len(cls.__match_args__)
, se lanzaTypeError
.De lo contrario, el patrón posicional
i
se convierte en un patrón de palabra clave utilizando__match_args__[i]
como palabra clave.__match_args__[i]
debe ser una cadena; si no, se lanzaTypeError
.Si hay palabras clave duplicadas, se lanza
TypeError
.
- II. Una vez que todos los patrones posicionales se hayan convertido en patrones de palabras clave,
la coincidencia procede como si solo hubiera patrones de palabras clave.
Para los siguientes tipos integrados, el manejo de subpatrones posicionales es diferente:
Estas clases aceptan un solo argumento posicional, y el patrón allí se compara con el objeto completo en lugar de con un atributo. Por ejemplo,
int(0|1)
coincide con el valor0
, pero no con el valor0.0
.
En términos simples, CLS(P1, attr=P2)
solo coincide si ocurre lo siguiente:
isinstance(<subject>, CLS)
convierta
P1
en un patrón de palabra clave usandoCLS.__match_args__
Para cada argumento de palabra clave
attr=P2
:hasattr(<subject>, "attr")
P2
coincide con<subject>.attr
… y así sucesivamente para el par de patrón / argumento de palabra clave correspondiente.
8.7. Definiciones de funciones¶
Una definición de función define una función objeto determinada por el usuario (consulte la sección Jerarquía de tipos estándar):
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
Una definición de función es una sentencia ejecutable. Su ejecución vincula el nombre de la función en el espacio de nombres local actual a un objeto de función (un contenedor alrededor del código ejecutable para la función). Este objeto de función contiene una referencia al espacio de nombres global actual como el espacio de nombres global que se utilizará cuando se llama a la función.
La definición de la función no ejecuta el cuerpo de la función; esto se ejecuta solo cuando se llama a la función. [4]
Una definición de función puede estar envuelta por una o más expresiones decorator. Las expresiones de decorador se evalúan cuando se define la función, en el ámbito que contiene la definición de la función. El resultado debe ser invocable, la cual se invoca con el objeto de función como único argumento. El valor retornado está vinculado al nombre de la función en lugar del objeto de la función. Se aplican múltiples decoradores de forma anidada. Por ejemplo, el siguiente código
@f1(arg)
@f2
def func(): pass
es más o menos equivalente a
def func(): pass
func = f1(arg)(f2(func))
excepto que la función original no está vinculada temporalmente al nombre func
.
Distinto en la versión 3.9: Las funciones se pueden decorar con cualquier assignment_expression
válido. Anteriormente, la gramática era mucho más restrictiva; ver PEP 614 para más detalles.
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.
Distinto en la versión 3.12: Type parameter lists are new in Python 3.12.
Cuando uno o más parameters tienen la forma parameter =
expression, se dice que la función tiene «valores de parámetros predeterminados». Para un parámetro con un valor predeterminado, el correspondiente argument puede omitirse desde una llamada, en cuyo caso se sustituye el valor predeterminado del parámetro. Si un parámetro tiene un valor predeterminado, todos los parámetros siguientes hasta el «*
» también deben tener un valor predeterminado — esta es una restricción sintáctica que la gramática no expresa.
Los valores de los parámetros predeterminados se evalúan de izquierda a derecha cuando se ejecuta la definición de la función. Esto significa que la expresión se evalúa una vez, cuando se define la función, y que se utiliza el mismo valor «precalculado» para cada llamada . Esto es especialmente importante para entender cuando un parámetro predeterminado es un objeto mutable, como una lista o un diccionario: si la función modifica el objeto (por ejemplo, al agregar un elemento a una lista), el valor predeterminado está en efecto modificado. Esto generalmente no es lo que se pretendía. Una forma de evitar esto es usar None
como valor predeterminado y probarlo explícitamente en el cuerpo de la función, por ejemplo:
def whats_on_the_telly(penguin=None):
if penguin is None:
penguin = []
penguin.append("property of the zoo")
return penguin
La semántica de llamadas de función se describe con más detalle en la sección Invocaciones. Una llamada a la función siempre asigna valores a todos los parámetros mencionados en la lista de parámetros, ya sea desde argumentos de posición, desde argumentos por palabra clave o desde valores predeterminados. Si está presente la forma «*identifier
», se inicializa en una tupla que recibe cualquier parámetro posicional excedente, por defecto en la tupla vacía. Si el formulario «**identifier
» está presente, se inicializa a una nueva asignación ordenada que recibe cualquier exceso de argumentos por palabra clave, por defecto a una nueva asignación vacía del mismo tipo. Los parámetros después de «*
» o «*identifier
» son parámetros solo por palabra clave y solo pueden pasarse con argumentos de palabras claves usadas.
Distinto en la versión 3.8: La sintaxis del parámetro de función /
se puede utilizar para indicar parámetros de posición únicamente. Consulte PEP 570 para obtener más detalles.
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.
Distinto en la versión 3.11: Parameters of the form «*identifier
» may have an annotation
«: *expression
». See PEP 646.
También es posible crear funciones anónimas (funciones no vinculadas a un nombre), para uso inmediato en expresiones. Utiliza expresiones lambda, descritas en la sección Lambdas. Tenga en cuenta que la expresión lambda es simplemente una abreviatura para una definición de función simplificada; una función definida en una sentencia «def
» puede pasarse o asignarse a otro nombre al igual que una función definida por una expresión lambda. La forma «def
» es en realidad más poderosa ya que permite la ejecución de múltiples sentencias y anotaciones.
Nota del programador: Las funciones son objetos de la primera-clase. Una sentencia «def
» ejecutada dentro de una definición de función define una función local que se puede retornar o pasar. Las variables libres utilizadas en la función anidada pueden acceder a las variables locales de la función que contiene el def. Vea la sección Nombres y vínculos para más detalles.
Ver también
- PEP 3107 - Anotaciones de funciones
La especificación original para anotaciones de funciones.
- PEP 484 - Sugerencias de tipo
Definición de un significado estándar para anotaciones: sugerencias de tipo.
- PEP 526 - Sintaxis para anotaciones variables
Ability to type hint variable declarations, including class variables and instance variables.
- PEP 563 - Evaluación pospuesta de anotaciones
Admite referencias directas dentro de las anotaciones conservando las anotaciones en forma de cadena de caracteres en tiempo de ejecución en lugar de una evaluación apresurada.
- PEP 318 - Decorators for Functions and Methods
Function and method decorators were introduced. Class decorators were introduced in PEP 3129.
8.8. Definiciones de clase¶
Una definición de clase define un objeto de clase (ver sección Jerarquía de tipos estándar):
classdef ::= [decorators
] "class"classname
[type_params
] [inheritance
] ":"suite
inheritance ::= "(" [argument_list
] ")" classname ::=identifier
Una definición de clase es una sentencia ejecutable. La lista de herencia generalmente proporciona una lista de clases base (consulte Metaclases para usos más avanzados), por lo que cada elemento de la lista debe evaluar a un objeto de clase que permita la subclasificación. Las clases sin una lista de herencia heredan, por defecto, de la clase base object
; por lo tanto,
class Foo:
pass
es equivalente a
class Foo(object):
pass
La suite de la clase se ejecuta en un nuevo marco de ejecución (ver Nombres y vínculos), usando un espacio de nombres local recién creado y el espacio de nombres global original. (Por lo general, el bloque contiene principalmente definiciones de funciones). Cuando la suite de la clase finaliza la ejecución, su marco de ejecución se descarta pero se guarda su espacio de nombres local. [5] Luego se crea un objeto de clase utilizando la lista de herencia para las clases base y el espacio de nombres local guardado para el diccionario de atributos. El nombre de la clase está vinculado a este objeto de clase en el espacio de nombres local original.
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.
La creación de clases se puede personalizar en gran medida usando metaclasses.
Las clases también se pueden decorar: al igual que cuando se decoran funciones,
@f1(arg)
@f2
class Foo: pass
es más o menos equivalente a
class Foo: pass
Foo = f1(arg)(f2(Foo))
Las reglas de evaluación para las expresiones de decorador son las mismas que para los decoradores de funciones. El resultado se vincula al nombre de la clase.
Distinto en la versión 3.9: Las clases se pueden decorar con cualquier assignment_expression
válido. Anteriormente, la gramática era mucho más restrictiva; ver PEP 614 para más detalles.
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.
Distinto en la versión 3.12: Type parameter lists are new in Python 3.12.
** Nota del programador: ** Las variables definidas en la definición de la clase son atributos de clase; son compartidos por instancias. Los atributos de instancia se pueden establecer en un método con self.name = value
. Se puede acceder a los atributos de clase e instancia a través de la notación «self.name
», y un atributo de instancia oculta un atributo de clase con el mismo nombre cuando se accede de esta manera. Los atributos de clase se pueden usar como valores predeterminados para los atributos de instancia, pero el uso de valores mutables puede generar resultados inesperados. Descriptors se puede usar para crear variables de instancia con diferentes detalles de implementación.
Ver también
- PEP 3115 - Metaclases en Python 3000
La propuesta que cambió la declaración de metaclases a la sintaxis actual y la semántica de cómo se construyen las clases con metaclases.
- PEP 3129 - Decoradores de clase
La propuesta que agregó decoradores de clase. Los decoradores de funciones y métodos se introdujeron en PEP 318.
8.9. Corrutinas¶
Added in version 3.5.
8.9.1. Definición de la función corrutina¶
async_funcdef ::= [decorators
] "async" "def"funcname
"(" [parameter_list
] ")" ["->"expression
] ":"suite
La ejecución de corrutinas de Python se puede suspender y reanudar en muchos puntos (consulte coroutine). Las expresiones await
, async for
y async with
solo se pueden utilizar en el cuerpo de una función de corrutina.
Las funciones definidas con la sintaxis async def
siempre son funciones de corrutina, incluso si no contienen palabras claves await
o async
.
Es un error del tipo SyntaxError
usar una expresión yield from
dentro del cuerpo de una función de corrutina.
Un ejemplo de una función corrutina:
async def func(param1, param2):
do_stuff()
await some_coroutine()
Distinto en la versión 3.7: await
y async
ahora son palabras clave; anteriormente solo se los trataba como tales dentro del cuerpo de una función de rutina.
8.9.2. La sentencia async for
¶
async_for_stmt ::= "async" for_stmt
Un asynchronous iterable proporciona un método __aiter__
que retorna directamente un asynchronous iterator, que puede llamar a código asincrónico en su método __anext__
.
La sentencia async for
permite una iteración apropiada sobre iteradores asincrónicos.
El siguiente código:
async for TARGET in ITER:
SUITE
else:
SUITE2
Es semánticamente equivalente a:
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
Consulte también __aiter__()
y __anext__()
para obtener más detalles.
Es un error del tipo SyntaxError
usar una sentencia async for
fuera del cuerpo de una función de corrutina.
8.9.3. La sentencia async with
¶
async_with_stmt ::= "async" with_stmt
Un asynchronous context manager es un context manager que puede suspender la ejecución en sus métodos enter y exit.
El siguiente código:
async with EXPRESSION as TARGET:
SUITE
es semánticamente equivalente a:
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)
Consulte también __aenter__()
y __aexit__()
para obtener más detalles.
Es un error del tipo SyntaxError
usar una sentencia async with
fuera del cuerpo de una función de corrutina.
Ver también
- PEP 492 - Corrutinas con sintaxis
async
yawait
La propuesta que convirtió a las corrutinas en un concepto independiente adecuado en Python, y agregó una sintaxis de soporte.
8.10. Type parameter lists¶
Added in version 3.12.
Distinto en la versión 3.13: Support for default values was added (see PEP 696).
type_params ::= "["type_param
(","type_param
)* "]" type_param ::=typevar
|typevartuple
|paramspec
typevar ::=identifier
(":"expression
)? ("="expression
)? typevartuple ::= "*"identifier
("="expression
)? paramspec ::= "**"identifier
("="expression
)?
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.
All three flavors of type parameters can also have a default value, which is used
when the type parameter is not explicitly provided. This is added by appending
a single equals sign (=
) followed by an expression. Like the bounds and
constraints of type variables, the default value is not evaluated when the
object is created, but only when the type parameter’s __default__
attribute
is accessed. To this end, the default value is evaluated in a separate
annotation scope. If no default value is specified
for a type parameter, the __default__
attribute is set to the special
sentinel object typing.NoDefault
.
The following example indicates the full set of allowed type parameter declarations:
def overly_generic[
SimpleTypeVar,
TypeVarWithDefault = int,
TypeVarWithBound: int,
TypeVarWithConstraints: (str, bytes),
*SimpleTypeVarTuple = (int, float),
**SimpleParamSpec = (str, bytearray),
](
a: SimpleTypeVar,
b: TypeVarWithDefault,
c: TypeVarWithBound,
d: Callable[SimpleParamSpec, TypeVarWithConstraints],
*e: 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): ...
This is equivalent to:
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.
Notas al pie