Juan Brodie
Estoy dando el Python typing
módulo un tiro.
Sé que es válido especificar la longitud de un List
como el siguiente*:
List[float, float, float] # List of 3 floats <-- NOTE: this is not valid Python
¿Hay alguna abreviatura para listas más largas? ¿Qué pasa si quiero configurarlo en 10 flotadores?
List[float * 10] # This doesn't work.
Cualquier idea si esto es posible, esto sería útil.
*NOTA: Resulta que proporcionar múltiples argumentos a Sequence[]
(y sus subclases) de esta manera actualmente NO es Python válido. Además, actualmente no es posible especificar un Sequence
longitud usando el typing
módulo de esta manera.
no puedes Una lista es mutable, Longitud variable estructura. Si necesita una estructura de longitud fija, use una tupla en su lugar:
Tuple[float, float, float, float, float, float, float, float, float, float]
O mejor aún, usa un tupla nombradaque tiene tanto índices como atributos con nombre:
class BunchOfFloats(NamedTuple):
foo: float
bar: float
baz: float
spam: float
ham: float
eggs: float
monty: float
python: float
idle: float
cleese: float
Una lista es simplemente el tipo de datos incorrecto para una estructura de datos de longitud fija.
-
Si está usando tupla, también puede usar puntos suspensivos literales, es decir
Tuple[int, ...]
según PEP484–Tomász Bartkowiak
23 de julio de 2019 a las 10:03
-
@TomaszBartkowiak: ese es el opuesto de lo que se pregunta. Sí, puede declarar una tupla de longitud variable que contenga un solo tipo de esa manera. Pero eso es no es un tamaño fijo.
– Martijn Pieters
♦23 de julio de 2019 a las 11:16
-
A veces, desea un contenedor mutable que tenga una longitud fija. Por ejemplo, si desea iniciar los elementos del contenedor en Ninguno, pero luego actualice los elementos con nuevos valores. Pero el contenedor seguiría siendo de tamaño fijo.
– Mate
23 de julio de 2020 a las 0:55
-
@Matt: claro, pero no hay un tipo de Python incorporado que le permita hacer eso, por lo que tampoco hay sugerencias de tipo.
– Martijn Pieters
♦25 de julio de 2020 a las 15:52
-
Para su información, la primera sugerencia de @MartijnPieters se puede abreviar como
Tuple[10 * (float, )]
que me parece bastante breve y ordenado, ya que expresa su propósito con mucha claridad.– balú
27 de abril de 2021 a las 8:34
Zaffy
typing.Annotated
puede ser útil aquí. Le permite especificar metadatos arbitrarios para escribir sugerencias:
Annotated[list[float], 3]
Nuevo en Annotated
? Aquí hay un fragmento de los documentos:
Si una biblioteca (o herramienta) encuentra una sugerencia de tipo
Annotated[T, x]
y no tiene una lógica especial para los metadatosx
debe ignorarlo y simplemente tratar el tipo comoT
.
Notablemente, mypy
tiene un solicitud pendiente (abierto a partir de noviembre de 2022) para algo como esto. Mientras tanto, piensa en Annotated
en cuanto a la legibilidad del desarrollador, no para la inspección automatizada (a menos que desarrolle herramientas de inspección).
-
Gracias, es bueno saber eso
typing.Annotated
existe — En mi humilde opinión, la respuesta debería explicar que el entero agregado3
funciona como un comentario adjunto a la variable anotada. Tiene que escribir sus propias herramientas para usar la anotación adicional. — Además de eso, agregar solo un número entero hará que la anotación adicional sea ambigua. Sería mejor crear una estructura para poder expresar el contexto, algo como:Annotated[List[float], Length[3]]
– pabouk – Ucrania se mantiene fuerte
16 de mayo a las 15:01
-
no estoy viendo
typing.Length
– ¿Eso realmente existe, o simplemente expresas el deseo de una nueva función?-Addison Klinke
27 de julio a las 15:25
raymond hettinger
Hasta ahora, solo las tuplas admiten especificar un número fijo de campos y no tiene atajos para un número fijo de repeticiones.
Aquí está la definición y la cadena de documentación del mecanografía módulo:
class Tuple(tuple, extra=tuple, metaclass=TupleMeta):
"""Tuple type; Tuple[X, Y] is the cross-product type of X and Y.
Example: Tuple[T1, T2] is a tuple of two elements corresponding
to type variables T1 and T2. Tuple[int, float, str] is a tuple
of an int, a float and a string.
To specify a variable-length tuple of homogeneous type, use Tuple[T, ...].
"""
__slots__ = ()
def __new__(cls, *args, **kwds):
if _geqv(cls, Tuple):
raise TypeError("Type Tuple cannot be instantiated; "
"use tuple() instead")
return _generic_new(tuple, cls, *args, **kwds)
Dado que las listas son un tipo mutable de longitud variable, no tiene ningún sentido utilizar una declaración de tipo para especificar un tamaño fijo.
-
Gracias Raymond, lo suficientemente claro. Si bien las dos respuestas que he recibido aquí son precisas y aclaratorias, todavía no estoy 100% seguro de cuál es la mejor manera de sugerir funciones que realmente necesitan una entrada de secuencia de longitud establecida. Supongo que simplemente poner esto en la cadena de documentación no es tan malo, pero parece una pena. (Realmente disfruto cómo PyCharm capta estas sugerencias en la ayuda generada para cada método)
– John Brodie
7 ago 2017 a las 15:39
-
“hasta ahora…” ¿Existe algún plan para especificar una secuencia mutable de longitud fija?
Generic
en eltyping
módulo en algún momento?– Rick
5 de febrero de 2018 a las 16:35
Cuando también me enfrenté al mismo problema, no me agradó ver la respuesta de Martijn Pieters. Ya que quería una forma “rápida” y “fácil” de resolver este problema.
Así que probé las otras sugerencias enumeradas aquí primero.
Nota: utilicé VSCode con Pylance como servidor de idioma
La respuesta de Zaffy fue mi favorita.
def demystify(mystery: Annotated[Tuple[int], 6]):
a, b, c, d, e, f = mystery
print(a, b, c, d, e, f)
Sugerencia para la función entonces se ve así: demystify: (mystery: Tuple[int]) -> None
También recibo un error de Pylance Tuple size mismatch: expected 6 but received
para la línea a, b, c, d, e, f = mystery
Luego probé Tuple[6 * (int, )]
que fue mencionado por balu en los comentarios de la respuesta de Martijn Pieters
def demystify(mystery: Tuple[6 * (int,)]):
a, b, c, e, f, g = mystery
print(a, b, c, e, f, g)
Resultando en el mismo error de Pylance que antes. La pista para la función fue esta: demystify: (mystery: Tuple[Tuple[Type[int], ...]]) -> None
Volviendo a escribir la longitud esperada:
def demystify(mystery: Tuple[int, int, int, int, int, int]):
a, b, c, e, f, g = mystery
print(a, b, c, e, f, g)
Esto resolvió el error de Pylance y me dio una sugerencia de función “clara”: demystify: (mystery: Tuple[int, int, int, int, int, int]) -> None
Pero al igual que John Brodie, no estaba contento con esta solución.
Ahora volvamos a la respuesta, al principio, no deseada:
class MysteryType(NamedTuple):
a: int
b: int
c: int
d: int
e: int
f: int
g: int
def demystify(mystery: MysteryType):
print(*mystery)
La sugerencia de función ahora parece más mística: demystify: (mystery: MysteryType) -> None
pero crear un nuevo MysteryType me da toda la información que necesito: (a: int, b: int, c: int, d: int, e: int, f: int, g: int)
También puedo usar MysteryType en otros métodos y funciones sin la necesidad de contar las sugerencias de tipo.
Entonces, para resumir una larga historia y parafrasear el Zen de Python:
NamedTuples es una gran idea, ¡hagamos más de eso!