Pycharm, Python 3 и подсказки типов

Python

Предисловие и предположения об окружающей среде

Pycharm 2017
Нижняя версия Pycharm не поддерживает Type Hint, поэтому здесь предполагается, что это относительно новая версия.

Python 3.5
В нынешнем сообществе Python 3 становится все более и более популярным, и несколько тяжеловесных библиотек/фреймворков больше не поддерживают 2. А 3.5 — более важная версия (если это новый проект, то обычно это сразу 3.5/3.6), поэтому в этой статье используется 3.5.

Статическая набравка важна
Поскольку я не являюсь соответствующим профессионалом, я буду называть это здесь так. Поскольку Python — динамический язык, Type Hint — это не то же самое, что статический тип вроде C++/Java, он используется только как подсказка из IDE (динамический язык выбран, а какой молоток нужен, так и используйте: )). К счастью, сейчас большинство людей используют программирование в среде IDE (имеется в виду написание производственного кода), поэтому Type Hint или что-то в этом роде по-прежнему стоит использовать.

Короче говоря, если Java/C++ уподобить ракетной пушке, то Type Hint легче. Глядя налево и направо, лучше использовать зажигалку, чем "сверлить дрова, чтобы развести огонь" :).

возможные потребности

Для аннотации типа у нас могут быть следующие требования.

Один из них — участие. По типу параметра его можно разделить на следующие категории:

  1. Основные встроенные типы, такие как str, int, list
  2. Сложные типы, полученные в результате комбинации примитивных типов, таких как list[int], dict[str, int]
  3. Пользовательские классы, такие как Person, Animal
  4. Параметры функции, а именно вызываемые, такие как параметры обратного вызова: (значение: str, индекс: int) => str

Второй — выходной параметр (возвращаемое значение). Это в основном то же самое, что и классификация входных параметров, и повторяться не будет.

Давайте посмотрим, как реализовать требования, перечисленные выше в пунктах 2 и 3 соответственно.

Второй способ Python: строка документа

Pycharm имеет относительно полную поддержку для этого, чего в принципе достаточно, единственный недостаток — громоздкость.

Пример выглядит следующим образом:

class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age

    def get_name(self):
        return self._name

    def get_age(self):
        return self._age


class Py2TypehintTester:
    def test1(self, a, b, c):
        """第一种需求
        
        基本很容易满足
        
        :type a: str
        :param a:
         
        :type b: str
        :param b: 
        
        :type c: list
        :param c: 
        
        :rtype: list
        :return: 
        """

        return [a, b, c]

    def test2(self, a, b, c):
        """第二种需求
        
        也很容易满足,只不过需要遵循 Pycharm 规定的语法, 它才能正确解析
        
        :type a: list[str]
        :param a: 
        
        :type b: list[int]
        :param b: 
        
        :type c: dict[str, int]
        :param c: 
        
        :rtype: dict[str, str]
        :return: 
        """

        for item in a:
            item.upper()

    def test3(self, p):
        """第三种需求
        
        也很容易满足.
        不过需要对应的 class 在本module 的空间内( 比如, 从别处 import 进来也是可以的)
        
        :type p: Person
        :param p: 
        :return: 
        """

        age = p.get_age()

    def test4(self, callback):
        """第四种需求
        
        会让你容易满足, 需要遵循特定写法
        
        :type callback: (str, int) -> str
        :param callback: 
        :return: 
        """

        s = 's'
        i = 1

        result = callback(s, i)
        print(result)  # 能正确推导为str

Преимущества этого метода очевидны, а именно: Нет никакой зависимости, просто следуйте предписанному методу написания.

Способ Python 3: подсказка типа

Этот способ официально предусмотрен, по сравнению с вышеописанным, он в принципе намного проще и интуитивно понятен, и может потребоваться некоторое время, чтобы к нему привыкнуть.

Пример выглядит следующим образом:

import typing  # 需求导入这个库

# 生成复合类型, 这段代码请无视
FloatVector = typing.List[float]
StrList = typing.List[str]
MyT = typing.TypeVar('T')


class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age

    def get_name(self):
        return self._name

    def get_age(self):
        return self._age


class Py3TypehintTester:
    def test1(self, a: str, b: str, c: str) -> list:
        """第一种需求

        很简单, 形式比较简洁

        :param a:
        :param b:
        :param c:
        :return:
        """
        return [a, b, c]

    def test2(self, a: typing.List[str], 
                    b: typing.List[str], 
                    c: typing.Dict[str, int]) -> typing.Dict[str, str]:
        """第二种需求

        比较简单, 需要先了解 typing 这个库

        :param a:
        :param b:
        :param c:
        :return:
        """

        return {
            'str': 'str1'
        }

    def test3(self, p: Person):
        """第三种需求

        比较简单

        :param p:
        :return:
        """

        print(p.get_age())

    def test4(self, callback: typing.Callable[[str, int], str]):
        """第四种需求
        
        稍复杂, 需要先仔细阅读下代码
        不过这种需求基本出现的频率不多, 倒也不影响大局
        
        :param callback: 
        :return: 
        """

        s = 's'
        i = 1
        result = callback(s, i)
        print(result)  # 能推导为str

мой подход

if >= 3.5:
    使用第二种,毕竟简洁许多,而且也没啥学习成本,十几分钟的事
    要求也比较高: 对 IDE 版本和 Python 版本均有要求
else:
    使用第一种,可以视作过渡吧,反正兼容性是最好的,哪个版本的 Pycharm 都能正确提示

приложение

  • Документация по подсказкам типа Pycharm: https://www.jetbrains.com/help/pycharm/type-hinting-in-pycharm.html