Разница между List[Optional[str]] и Iterable[str]

Установил mypy и при анализе строчки кода ",".join(ids[:50])

ids: List[Optional[str]] = ["text","test"]
error: Argument 1 to "join" of "str" has incompatible type "List[Optional[str]]"; expected "Iterable[str]"

Почему это ошибка? Разве список не итерируемый объект? Какая разница между списком и Iterable и в каких случаях что выбирать?


Ответы (2 шт):

Автор решения: Daniil Loban

В качестве ответа вопрос:"Какая разница между списком и Iterable и в каких случаях что выбирать?" можно привести пример,

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self

  def __next__(self):
    if self.a <= 20:
      x = self.a
      self.a += 1
      return x
    else:
      raise StopIteration

myclass = MyNumbers()

for x in myclass:
  print(x)

В результате выполнения мы получим числа от 1 до 20. myclass является итерируемым объектом, в то же время он генерирует свои значения во время исполнения, в отличие от списка который всегда сформирован. Список имеет в себе итератор, как и строка, они возвращают его с помощью метода iter() таким образом мы получаем разницу между списком и итератором:

list != iter(list)

→ Ссылка
Автор решения: insolor

Проблема не в List/Iterable, а в Optional. List[Optional[str]] подразумевает то, что список может содержать строки или None, но join не умеет соединять значения None, требуемый тип принимаемого значения у него - Iterable[str], т.е. итерируемый объект из строк (строго из строк, никаких None). Если убрать Optional, то ошибка исчезнет.

Пример кода:

from typing import List


ids: List[str] = ["text","test"]
print(", ".join(ids))

Вывод mypy:

Success: no issues found in 1 source file

mypy на Optional ругается не просто так: ваша аннотация предполагает, что возможен список такого вида ["text", None], при применении join к которому вылетит ошибка TypeError: sequence item 1: expected str instance, NoneType found.

→ Ссылка