Почему я получаю предупреждение при объединении списков смешанных типов в Pycharm? - PullRequest
3 голосов
/ 24 июня 2019

В Pycharm следующий код выдает предупреждение:

from typing import List

list1: List[int] = [1, 2, 3]
list2: List[str] = ["1", "2", "3"]
list3: List[object] = list1 + list2
#                             ↳ Expected type List[int] (matched generic type List[_T]),
#                               got List[str] instead.

Почему?Разве я не должен объединять два списка смешанных, намекаемых типов?

Ответы [ 2 ]

3 голосов
/ 25 июня 2019

Как просили в комментариях, вот несколько причин, почему проверки типов не позволяют этого.

Первая причина несколько прозаична: сигнатура типа list.__add__ просто не допускает ничего, кроме списка, содержащего тот же тип, для передачи:

_T = TypeVar('_T')

# ...snip...

class list(MutableSequence[_T], Generic[_T]):

    # ...snip...

    def __add__(self, x: List[_T]) -> List[_T]: ...

А Pycharm, который поддерживает PEP 484, использует (частично) данные из Typeshed.

Возможно, что мы могли бы каким-то образом расширить сигнатуру типа (например, перегрузить ее, чтобы также принять List[_S] и вернуть List[Union[_T, _S]] в этом случае), но я не думаю, что кто-то беспокоился о том, чтобы исследовать выполнимость этого подход: такого рода вещи не слишком полезны на практике, усложняют жизнь людям, которые хотят строго однородных списков или хотят подклассировать их, и потенциально могут нарушить много существующего кода, который опирается на текущий тип подписи.

Эта сигнатура типа также, вероятно, является отражением более широкого выбора, сделанного во время первоначального проектирования PEP 484, чтобы предположить, что списки всегда однородны - всегда содержат значения одного и того же типа.

Разработчикам PEP 484, строго говоря, не нужно было делать этот выбор: они могли требовать проверки типов для взаимодействия с ним в особом случае, как мы в настоящее время делаем для кортежей. Но в целом проще не делать этого, я думаю. (И, возможно, лучший стиль, но все равно.)


Вторая причина связана с фундаментальным ограничением системы типов PEP 484: нет способа объявить, что какая-то функция или метод не изменяет состояние.

По сути, ваше поведение безопасно только в том случае, если гарантировано, что lst1.__add__(lst2) не мутирует ни один из операндов. Но на самом деле нет никакой возможности гарантировать это - что если lst1 - это какой-то странный подкласс списка, который копирует элементы из lst2 в себя? Тогда временно ослаблять тип lst1 с SomeListSubtype[int] до SomeListSubtype[object] было бы небезопасно: lst1 больше не будет содержать только целые числа после добавления / вставки строк из lst2.

Конечно, на самом деле написание такого подкласса также является плохой практикой, но средства проверки типов не могут позволить себе роскошь предполагать, что пользователи будут следовать передовым методам, если они не применяются принудительно: средства проверки типов, компиляторы и подобные инструменты являются в основном консервативными. звери.


И, наконец, стоит отметить, что ни одна из этих проблем не является непреодолимой. Есть несколько вещей, которые могут быть реализованы средствами проверки типов, например:

  1. Работа с сигнатурой типа списка (и проверка того, что она не нарушает существующий код)
  2. Ввести какой-то способ объявить, что метод является чистым - не имеет мутаций. По сути, обобщите идеи PEP 591 и примените их к функциям. (Но это потребует написания PEP, изменения typehed для использования новой конструкции ввода, выполнения тщательного проектирования и реализации ...)
  3. Может быть, это особый случай, когда мы знаем наверняка, что две переменные не являются подклассами списков. (Но на самом деле количество раз, когда мы наверняка узнаем это, довольно ограничено.)

... и т. Д.

Но все эти вещи требуют времени и энергии: это вопрос расстановки приоритетов. Средство отслеживания проблем для Pycharm (и mypy, и т. Д.) Довольно длинное, и нет недостатка в других ошибках / запросах функций для обработки.

0 голосов
/ 24 июня 2019

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

...