После изучения баз данных SQL с помощью Python и Flask, здесь и здесь, сегодня я хотел представить концепцию подсказок типов в Python, варианты их использования, а также их плюсы и минусы. Типовые подсказки могут быть отличными инструментами для улучшения читабельности вашего кода, но они не всегда являются лучшим решением.

Этот пост задуман как введение в эту тему для начинающих, и я могу написать больше, если будет больше интереса. В результате я ожидаю, что это будет легкое и быстрое чтение. Если у вас есть какие-либо комментарии или предложения, дайте мне знать в разделе комментариев ниже.

Что такое подсказки типов Python?

Подсказки типов Python были впервые представлены в PEP 484 и появились в Python 3.5. Как следует из названия, подсказки типов — это подсказки о типе переменных или объектов в вашем коде.

Они позволяют вам объявлять тип переменных и возвращать типы ваших функций. Однако это не означает, что подсказки типов делают Python статически типизированным. Это просто «подсказки», означающие, что они не влияют на работу вашей программы.

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

Хотя подсказки типов были доступны уже некоторое время, каждая новая версия Python добавляет новые функции. Следующие примеры были написаны с учетом Python 3.9.4. Если вы получаете ошибки при запуске кода, возможно, сначала убедитесь, что вы используете совместимую версию.

Аннотирование простых переменных

Первый пример будет посвящен аннотированию основных типов Python в переменных:

x:int = 10 
f: float = 0.4 
name:str = "hello"

Как видите, мы сообщаем IDE, что x — это переменная int, f — это число с плавающей запятой, а name — это str. Основной синтаксис для подсказки типа заключается в том, чтобы ввести имя вашей переменной, за которым следует двоеточие, а затем базовый тип Python.

Однако помните, что подсказки типов — это всего лишь предложение и они не применяются во время выполнения кода (хотя я думаю, что определенные среды выполнения могут их применять). Я мог бы легко изменить значения переменных следующим образом:

x: int = 100 
# I can assign any value to x 
x = "Janice"

Я также могу установить неправильное значение с самого начала:

x:int = "this is a string"

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

Наконец, вы даже можете аннотировать переменные перед тем, как присвоить им значение:

a:int #a has no value yet 
# ... do something here 
my_str = "this is a string" 
a = len(my_str) #we only now assign a value to a

Аннотирование объектов-контейнеров (словари, списки, кортежи и т. д.)

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

# here I'm stating that my_list will 
#  only contain str and int values 
from typing import Union
my_list: list[Union[str, int]]

В приведенном выше примере вы можете видеть, что мы объявляем, что список может содержать как строки, так и целые числа.

Следующий пример предназначен для аннотирования словарей Python. В случае с dicts необходимо аннотировать два элемента: ключи и значения. Вот пример синтаксиса:

# simple annotation where keys and values are strings 
simple_dict: dict[str, str] = {
 'city' : 'London', 
 'Country' : 'UK', 
 'name' : 'James' 
}

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

#use "typing" module 
from typing import Union, Any 
my_dict: dict[str, Union[str,int,float,None,Any]] = { 
    'name' : 'James', 
    'age' : 20, 
    'height' : 1.8, 
}

В примере мы указываем, что значения словаря могут быть следующими: str, int, float, None или Any. Мы используем импорт, чтобы указать, что значение может быть любым из указанных вариантов. Тип представляет собой универсальное выражение, совместимое со всеми другими типами. Это в основном указывает, что любой тип является приемлемым.

Я также должен упомянуть, что в Python 3.10, следуя PEP 604, вы можете напрямую аннотировать несколько типов без импорта файлов . Вместо этого вы можете использовать сочетание клавиш |, как в следующем примере:

# annotation for Python 3.10 
my_dict: dict[str, str|int|float|None|Any] = { 
    'name' : 'James', 
    'age' : 20, 
    'height' : 1.8, 
}

Аннотация функции

Типовые подсказки также можно использовать для аннотирования функций и возвращаемых ими типов. Вот пример:

#add ints or floats 
def add_numbers(a:Union[int,float], b:Union[int,float]) -> Union[int,float]: 
    return a + b 
#function that does not return anything 
def good_morning(name:str) -> NoReturn: 
    print(f"Good morning {name}!")

В первом случае я снова использую модуль typing для импорта Union. Во втором примере используется, чтобы указать, что функция выполняет не возвращать значение.

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

from typing import Optional 
#function with optional parameters 
def some_function(a:int, b:str, c:Optional[Union[int,float]]) -> int: 
    pass

В этом случае мы используем, чтобы указать, что значение может быть любым из упомянутых или . В основном это эквивалентно выполнению: Union[int, float, None].

Пользовательские классы и типы

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

class SimpleClass(object): 
    number = 10 
    text = "SimpleClass" 
a: type[SimpleClass] = SimpleClass()

Таким образом, используя ключевое слово type, мы можем указать собственный класс типов. Это будет работать и для функций, когда нам нужно вернуть этот класс или взять его в качестве параметра:

def alter_class(my_class: type[SimpleClass]) -> type[SimpleClass]:
    my_class.name = 20 
    return my_class

В этом примере функция alter_class принимает объект типа SimpleClass и возвращает объект того же типа.

За и против

Теперь, когда я рассмотрел некоторые из основных доступных типовых подсказок, я хотел бы упомянуть их плюсы и минусы.

Плюсы типовых подсказок

  • Подтолкнуть вас к более тщательному обдумыванию вашего кода и ваших переменных
  • IDE и линтеры лучше поймут ваш код и могут даже предупредить вас, если вы допустили ошибку.
  • Типовые подсказки — это быстрый способ получить самодокументирующийся код.

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

Мое личное мнение

Я не очень часто использовал подсказки, но потихоньку добираюсь до этого. С одной стороны, при правильном использовании они могут внести большую ясность при перечитывании того, что я написал. С другой стороны, мне не нравится, что это просто предложения. Мне было бы гораздо удобнее тратить время на их использование, если бы я знал, что они будут уважаемы. Я думаю, что можно легко забыть, что эти аннотированные переменные могут принимать любое значение в любой момент. Надеюсь, IDE могут помочь в этом.

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

И я, безусловно, вижу пользу в использовании подсказок типа в больших проектах кода. Особенно те, которые поддерживаются многими разными людьми в разное время. Для быстрых одноразовых скриптов это, вероятно, не стоит слишком много.

Последние мысли

Сегодня я представил базовое введение в подсказки типов Python. Они существуют уже некоторое время, но я не вижу, чтобы они широко использовались, поэтому я хотел объяснить их здесь.

Оставьте комментарий ниже с любыми предложениями или мнениями по этому посту. Я очень ценю это. Также не забудьте подписаться на рассылку, если хотите оставаться на связи.

Вы также можете подписаться на мой канал YouTube для видео о проектах Python, автоматизации и криптографии:

Наконец, если вы хотите оставаться на связи и быть в курсе того, что я публикую, вы можете подписаться на мою новостную рассылку здесь. Я хочу, чтобы этот информационный бюллетень был полезным источником советов и приемов, которые я узнаю, а также местом для обсуждения новых проектов, над которыми я мог бы работать в будущем.

Первоначально опубликовано на https://andresberejnoi.com 28 марта 2022 г.