Benjamín
Tengo una función que usa el len
funciona en uno de sus parámetros e itera sobre el parámetro. Ahora puedo elegir si anotar el tipo con Iterable
o con Sized
pero ambos dan errores en mypy
.
from typing import Sized, Iterable
def foo(some_thing: Iterable):
print(len(some_thing))
for part in some_thing:
print(part)
Da
error: Argument 1 to "len" has incompatible type "Iterable[Any]"; expected "Sized"
Tiempo
def foo(some_thing: Sized):
...
Da
error: Iterable expected
error: "Sized" has no attribute "__iter__"
Como no hay Intersection
como se discutió en este problema Necesito tener algún tipo de clase mixta.
from abc import ABCMeta
from typing import Sized, Iterable
class SizedIterable(Sized, Iterable[str], metaclass=ABCMeta):
pass
def foo(some_thing: SizedIterable):
print(len(some_thing))
for part in some_thing:
print(part)
foo(['a', 'b', 'c'])
Esto da un error al usar foo
con un list
.
error: Argument 1 to "foo" has incompatible type "List[str]"; expected "SizedIterable"
Esto no es demasiado sorprendente ya que:
>>> SizedIterable.__subclasscheck__(list)
False
Así que definí un __subclasshook__
(ver documentos).
class SizedIterable(Sized, Iterable[str], metaclass=ABCMeta):
@classmethod
def __subclasshook__(cls, subclass):
return Sized.__subclasscheck__(subclass) and Iterable.__subclasscheck__(subclass)
Entonces la comprobación de la subclase funciona:
>>> SizedIterable.__subclasscheck__(list)
True
Pero mypy
todavía se queja de mi list
.
error: Argument 1 to "foo" has incompatible type "List[str]"; expected "SizedIterable"
¿Cómo puedo usar sugerencias de tipo cuando uso tanto el len
función e iterar sobre mi parámetro? creo que el casting foo(cast(SizedIterable, ['a', 'b', 'c']))
no es una buena solución.
A partir de Python3.6 hay un nuevo tipo llamado Collection
. Ver aquí.
-
Es
Collection
preferible aIterator
cuando ellen()
se usa la funcion?– kctong529
23 oct 2018 a las 14:34
-
Un
Iterator
no tiene talla Mira aquí: docs.python.org/3/library/…– Una vision
25/10/2018 a las 11:50
-
PyCharm parece advertir aún cuando es un ItemView (dict.items())
– usuario972014
25 de agosto de 2019 a las 7:02
-
Value of type "Collection[Any]" is not indexable
… ¿hay un tipo para algo sobre lo que pueda iterar, pueda llamar a len() y obtener un elemento por índice?– James Owers
9 de abril de 2020 a las 16:56
-
@JamesOwers: Esa es una secuencia.
– usuario2357112
11 de abril de 2020 a las 11:13
hans
deberías ir con Sequence
de mecanografía si planea usar solo una lista o una tupla y acceder a sus elementos por índice, como x[0]
. Sequence
es ambos Sized
y Iterable
ver aquí.
-
Esto no funcionará para conjuntos regulares y congelados. no implementan
__getitem__
como se esperaba de las secuencias.–Olivier Desenfans
28 de marzo de 2020 a las 11:04
-
Buen punto. Solo funciona con un indexable (que implementa
__getitem__
), como una lista o una tupla. En un caso más general, utiliceCollection
como sugiere Avision.– hans
16 de abril de 2020 a las 9:10
-
Las secuencias son
Iterable
como consecuencia de necesitar la__getitem__
método, no simplemente serIterable
.– Alex Loss
11 de agosto de 2020 a las 20:09
En el futuro Protocol
Se introducirán s. Ya están disponibles a través de typing_extensions
. Ver también PEP 544. Usando Protocol
el codigo de arriba seria:
from typing_extensions import Protocol
class SizedIterable(Protocol):
def __len__(self):
pass
def __iter__(self):
pass
def foo(some_thing: SizedIterable):
print(len(some_thing))
for part in some_thing:
print(part)
foo(['a', 'b', 'c'])
mypy
toma ese código sin quejarse. Pero PyCharm está diciendo
Tipo esperado ‘SizedIterable’, obtuvo ‘Lista[str]’
sobre la última línea.
-
Las definiciones de protocolo ya han sido introducido en Pitón 3.8.
– Jeyekomon
16 de febrero de 2021 a las 13:56
Sinri Edogawa
¿Tal vez necesitas una clase como esta?
class MyArray:
_array: list
def as_tuple(self):
return tuple(self._array)
def as_list(self):
return self._array
# More Feature to implement