Аннотации переменных в Python
Аннотации переменных — следующий шаг развития аннотаций типов. Сегодня мы подробно расскажем, что они из себя представляют и как их использовать.
В Python 3.6 появилась такая интересная особенность, как синтаксис для аннотаций переменных. Подробнее про это нововведение можно прочитать в PEP 526. Суть этого PEP заключается в том, чтобы перевести идею аннотаций типов (PEP 484) на её следующую логическую ступень, т.е. сделать возможным указание типов переменных, включая поля классов и объектов.
Следует принять во внимание, что это нововведение не делает Python статически типизированным языком. Интерпретатору всё равно, какой тип указан у переменной. Тем не менее в среде разработки на Python или другом инструменте вроде pylint может быть включена функция проверки аннотаций, которая сообщит вам, если вы сначала указали один тип переменной, а затем попытались использовать её в качестве другого типа далее в программе.
Давайте взглянем на простой пример, чтобы посмотреть, как это работает:
# annotate.py name: str = 'Mike'
В нашем файле annotate.py мы создали переменную name и добавили аннотацию, говорящую о том, что это строка. Аннотацию можно добавить, поставив двоеточие после имени переменной и затем указав нужный тип. Присваивать значение переменной вовсе не обязательно:
# annotate.py name: str
Прим.перев. Указать тип в Python 3.5 подобным образом не выйдет. Вместо этого есть возможность указывать тип в комментарии:
# annotate.py name = 'Mike' # type: str
Все переменные с аннотациями добавляются в атрибут __annotations__ модуля или класса. Давайте импортируем первую версию нашего модуля annotate и получим доступ к этому атрибуту:
>>> import annotate >>> annotate.__annotations__ > >>> annotate.name 'Mike'
Как вы видите, атрибут __annotations__ возвращает словарь с аннотацией в качестве значения. Давайте добавим ещё несколько аннотаций в наш модуль и посмотрим, как изменится атрибут __annotations__ :
# annotate.py name: str = 'Mike' ages: list = [12, 20, 32] class Car: variable: dict
В этом примере мы добавили список с аннотацией и класс, содержащий переменную с аннотацией. Теперь давайте импортируем новую версию нашего модуля и посмотрим на атрибут __annotations__ :
>>> import annotate >>> annotate.__annotations__ , 'ages': > >>> annotate.Car.__annotations__ > >>> car = annotate.Car() >>> car.__annotations__ >
В этот раз в словаре находится два объекта. Как вы могли заметить, в нём нет поля класса. Чтобы получить к нему доступ, мы должны обратиться к классу Car напрямую или создать экземпляр класса и получить атрибут таким образом.
Заключение
Теперь вы знаете достаточно о такой особенности Python, как аннотации переменных. Она будет особенно полезна программистам, привыкшим работать со статически типизированными языками.
Как задать тип возвращаемого значения функции в Python?
Для того, чтобы задать тип возвращаемого значения функции, используем аннотацию типов. Тип возвращаемого значения указывается после аргументов функции. Добавляем символы «->»,пробел и указываем тип. После чего ставим завершающее двоеточие:
def my_function(number1: int, number2: int) -> int: result = number1 + number2 .
Python. Урок 18. Аннотация типов в Python
Этот урок посвящен аннотациям типов в Python. Рассмотрен вопрос контроля типов переменных и функций с использованием комментариев и аннотаций. Приведено описание PEP‘ов, регламентирующих работу с аннотациями, и представлены примеры работы с инструментом mypy для анализа Python кода.
- Зачем нужны аннотации?
- Контроль типов в Python
- Обзор PEP’ов регламентирующий работу с аннотациями
- Использование аннотаций в функциях
- Указание типа аргументов и возвращаемого значения
- Доступ к аннотациям функции
- Создание аннотированных переменных
- Контроль типов с использованием аннотаций
Зачем нужны аннотации?
Для начала ответим на вопрос: зачем нужны аннотации в Python ? Если кратко, то ответ будет таким: для того чтобы повысить информативность исходного кода, и иметь возможность с помощью сторонних инструментов производить его анализ. Одной из наиболее востребованных, в этом смысле, тем является контроль типов переменных. Несмотря на то, что Python – это язык с динамической типизацией, иногда возникает необходимость в контроле типов.
Согласно PEP 3107 могут быть следующие варианты использования аннотаций:
- проверка типов;
- расширение функционала IDE в части предоставления информации об ожидаемых типах аргументов и типе возвращаемого значения у функций;
- перегрузка функций и работа с дженериками;
- взаимодействие с другими языками;
- использование в предикатных логических функциях;
- маппинг запросов в базах данных;
- маршалинг параметров в RPC (удаленный вызов процедур).
Контроль типов в Python
Рассмотрим небольшую демонстрацию того, как решался вопрос контроля типов в Python без использования аннотаций. Один из возможных вариантов (наверное самый логичный) решения данной задачи – это использование комментариев, составленных определенным образом.
Выглядит это так:
name = "John" # type: str
Мы создали переменную с именем name и предполагаем, что ее тип – str . Естественно, для самого интерпретатора Python это не имеет значения, мы, без труда можем продолжить нашу мини программу таким образом.
name = "John" # type: str print(name) name = 10 print(name)
И это будет корректно с точки зрения Python . Но если необходимо проконтролировать, что переменной name будут присваиваться значения только строкового типа, мы должны: во-первых указать в комментарии о нашем намерение – это мы сделали, во-вторых использовать специальный инструмент, который выполнит соответствующую проверку. Таким инструментом является mypy .
Установить его можно с помощью pip :
python -m pip install mypy
Если мы сохраним приведенный выше код в файле type_tester.py и выполним следующую команду:
python -m mypy test_type.py
Получим такое сообщение:
test_type.py:3: error: Incompatible types in assignment (expression has type “int”, variable has type “str”)
Оно говорит о том, что обнаружено несоответствие типов в операции присваивание: переменная имеет тип “ str “, а ей присвоено значение типа “ int “.
Обзор PEP’ов регламентирующий работу с аннотациями
Начнем наше введение в тему аннотаций в Python с краткого обзора четырех ключевых документов:
Первый из них PEP 3107 — Function Annotations , является исторически первым из перечисленных выше документов. В нем описывается синтаксис использования аннотаций в функциях Python . Важным является то, что аннотации не имеют никакого семантического значения для интерпретатора Python и предназначены только для анализа сторонними приложениями. Аннотировать можно аргументы функции и возвращаемое ей значение.
Следующий документ – PEP 484 — Type Hints . В нем представлены рекомендации по использованию аннотаций типов. Аннотация типов упрощает статический анализ кода, рефакторинг, контроль типов в рантайме и кодогенерацию, использующую информацию о типах. В рамках данного документа, определены следующие варианты работы с аннотациями: использование аннотаций в функциях согласно PEP 3107, аннотация типов переменных через комментарии в формате # type: type_name и использование stub -файлов (см. разделы Использование аннотаций в функциях и Аннотация переменных).
В PEP 526 — Syntax for Variable Annotations приводится описание синтаксиса для аннотации типов переменных (базируется на PEP 484), использующего языковые конструкции, встроенные в Python (см. раздел Аннотация переменных).
PEP 563 — Postponed Evaluation of Annotations . Данный PEP вступил в силу с выходом Python 3.7. У подхода работы с аннотация до этого PEP’а был ряд проблем связанных с тем, что определение типов переменных (в функциях, классах и т.п.) происходит во время импорта модуля, и может сложится такая ситуация, что тип переменной объявлен, но информации об этом типе ещё нет, в таком случае тип указывают в виде строки – в кавычках. В PEP 563 предлагается использовать отложенную обработку аннотаций, это позволяет определять переменные до получения информации об их типах и ускоряет выполнение программы, т.к. при загрузке модулей не будет тратится время на проверку типов – это будет сделано перед работой с переменными.
Теперь более подробно остановимся на использовании аннотаций, опираясь на перечисленные выше PEP ’ы.
Использование аннотаций в функциях
Указание типов аргументов и возвращаемого значения
В функциях мы можем аннотировать аргументы и возвращаемое значение. Выглядеть это может так.
def repeater(s: str, n: int) -> str: return s * n
Аннотация для аргумента определяется через двоеточие после его имени.
имя_аргумента: аннотация
Аннотация, определяющая тип возвращаемого функцией значения, указывается после ее имени с использованием символов ->
def имя_функции() -> тип
Для лямбд аннотации не поддерживаются.
Доступ к аннотациям функции
Доступ к использованным в функции аннотациям можно получить через атрибут __annotations__ , в котором аннотации представлены в виде словаря, где ключами являются атрибуты, а значениями – аннотации. Возвращаемое функцией значение хранится в записи с ключом return .
Содержимое repeater. __annotations__
Аннотация переменных
Создание аннотированных переменных
Можно использовать один из трех способов создания аннотированных переменных.
var = value # type: annotation var: annotation; var = value var: annotation = value
Рассмотрим это на примере работы со строковой переменной с именем name.
name = “John” # type: str name:str; name = “John” name: str = “John”
Приведем еще несколько примеров.
# список scores: List[int] = [] scores.append(1) # кортеж pack: Tuple[int, …] = (1, 2, 3) # логическая переменная flag: bool flag = True # класс class Point: x: int y: int def __init__(self, x: int, y: int): self.x = x self.y = y
Контроль типов с использованием аннотаций
Для проверки можно использовать уже знакомый нам инструмент mypy . Напишем вот такой код.
a:int = 10 b:int = 15 def sq_sum(v1:int, v2:int) -> int: return v1**2 + v2**2 print(sq_sum(a, b))
Сохраним его в файле с именем work.py и запустим mypy для анализа.
python -m mypy work.py
Если не указывать дополнительные ключи, то окно консоли будет чистым, т.к. mypy не найдет никаких ошибок в вашем коде.
Но если заменить первую строку
a: int = 10
a = 10.3
и вновь запустить mypy , то увидим вот такое сообщение:
work.py:7: error: Argument 1 to “sq_sum” has incompatible type “float”; expected “int”
При этом, естественно, код будет выполняться без всяких проблем, потому что интерпретатор Python в данном случае не обращает внимание на аннотации.
Отложенная проверка аннотаций
До выхода Python 3.7 определение типов в аннотациях происходило во время импорта модуля, что приводило к проблеме. Например, если выполнить следующий код:
class Rectangle: def __init__(self, height: int, width: int, color: Color) -> None: self.height = height self.width = width self.color = color
То возникнет ошибка NameError: name ‘Color’ is not defined. Она связана с тем, что переменная color имеет тип Color, который пока ещё не объявлен.
В таком случае, мы можем указать тип Color в кавычках, но это не очень удобно.
class Rectangle: def __init__(self, height: int, width: int, color: "Color") -> None: self.height = height self.width = width self.color = color
Эту проблему можно решить воспользовавшись отложенной обработкой аннотаций из Python 3.7.
from __future__ import annotations class Rectangle: def __init__(self, height: int, width: int, color: Color) -> None: self.height = height self.width = width self.color = color class Color: def __init__(self, r: int, g: int, b: int) -> None: self.R = r self.G = g self.B = b rect = Rectangle(1, 2, Color(255, 255, 255))
Можете проверить, что без строки from __future__ import annotations эта программа выполняться не будет.
P.S.
Если вам интересна тема анализа данных, то мы рекомендуем ознакомиться с библиотекой Pandas. На нашем сайте вы можете найти вводные уроки по этой теме. Все уроки по библиотеке Pandas собраны в книге “Pandas. Работа с данными”.
Раздел: Python Уроки по Python Метки: Python, аннотации в Python, Уроки Python
Python. Урок 18. Аннотация типов в Python : 2 комментария
- Алексей 08.11.2020 Благодарю, хорошее объяснение.
Указание типа переменной в python?
Объясните, имеет ли вообще смысл указывать тип аргументов? Единственный плюс (даже не питона, а среды), который я нашел, это то, что PyCharm при указании типа аргумента будет знать тип переменной и будет предлагать методы этого класса при написании variable.
Отслеживать
6,343 5 5 золотых знаков 25 25 серебряных знаков 54 54 бронзовых знака
задан 24 янв 2018 в 15:41
113 1 1 золотой знак 1 1 серебряный знак 5 5 бронзовых знаков
24 янв 2018 в 15:52
Подробнее можно прочитать здесь: PEP 3107 — Function Annotations
12 фев 2019 в 12:483 ответа 3
Сортировка: Сброс на вариант по умолчанию
Указания типов могут быть полезны не только для IDE или линтеров, но и для самого разработчика, особенно, если он начинающий. Немудрено запутаться в коде и переменных, если код не очень ловко написан и типы явно не указаны. Для начала можете указывать, а потом можете от этого и отказаться.
Отслеживать
ответ дан 24 янв 2018 в 17:32
Vadim Toptunov Vadim Toptunov
345 2 2 серебряных знака 7 7 бронзовых знаковНа сегодняшний день аннотации переменных полезны только для IDE и линтеров. Впрочем, на мой взгляд, и эта полезность сомнительна.
Отслеживать
ответ дан 24 янв 2018 в 15:48
Sergey Gornostaev Sergey Gornostaev
66.4k 6 6 золотых знаков 51 51 серебряный знак 112 112 бронзовых знаков
Эээээ, полезность линтеров сомнительна??
24 янв 2018 в 17:18
@andreymal полезность аннотаций сомнительна.
24 янв 2018 в 17:20Аннотации упрощают линтерам анализ и обнаружение ошибок, значит сомнительность полезности аннотаций сомнительна, я чего-то не понимаю?)
24 янв 2018 в 17:20
Это не питонично 🙂 Я склонен считать, что в динамическом языке следует иначе строить правильный код, так чтобы необходимости проверять типы просто не возникало.
24 янв 2018 в 17:34
@SergeyGornostaev, и вообще лучше писать код сразу без ошибок, ага.
24 янв 2018 в 18:44Указание типов как минимум позволяет раньше обнаружить ошибки.
Допустим у вас в функции есть несколько ветвей. Одна из них выполняется редко, но для успешного выполнения требуется строгое соответствие типа. В других ветвях происходит автоматическое преобразование и функция молча выполняет свою работу (не зависимо от соответствия этого преобразования вашим идеям). В этом случае при указании типов ошибка может проявиться еще на этапе трансляции
Отслеживать
ответ дан 24 янв 2018 в 15:48
tutankhamun tutankhamun
11.3k 5 5 золотых знаков 25 25 серебряных знаков 40 40 бронзовых знаков
насколько я знаю, Python не будет делать проверку типов даже в этом случае.
24 янв 2018 в 15:53- python
- функции
- типы-данных
-
Важное на Мете
Связанные
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.11.15.1019
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.