Как быстро найти проблемы с типами в вашем коде Python с помощью Pytype
Если вы работаете над большим проектом Python или просто хотите, чтобы ваша кодовая база была аккуратной, Pytype - это инструмент для вас.
Python - отличный язык программирования для прототипирования и написания сценариев. Краткий синтаксис, гибкая система типов и интерпретируемая природа позволяют нам быстро попробовать идею, настроить ее и повторить попытку.
Когда проекты Python растут, гибкость, которая когда-то обеспечивала скорость, становится бременем для скорости разработки. По мере того, как к проекту присоединяются дополнительные разработчики и пишется все больше кода, отсутствие информации о типе затрудняет чтение и понимание кода. Без системы проверки типов ошибки легко допустить и их трудно обнаружить.
Pytype вам в помощь! Pytype - это инструмент с открытым исходным кодом для проверки типов и вывода типов в Python. И это работает "из коробки" - просто установите и запустите!
Pytype будет:
- Проанализирует статические типы и проверит ваш код на наличие ошибок типов.
- Проверит на согласованность аннотации типа PEP 484 в вашем коде.
- Если хотите, поможет добавить статичные типы в ваш код
Вы можете пройти на страницу Pytype для получения инструкций по установке и использованию. Ниже я привожу несколько интересных примеров использования!
Пример 1: Вывод типа и проверка
Это самый распространенный сценарий. Вы написали некоторый код и хотите проверить исправность, чтобы не допустить ошибок. Рассмотрим эту функцию:
import re def GetUsername(email_address): match = re.match(r'([^@]+)@example\.com', email_address) return match.group(1)
Довольно просто. Он извлекает часть адреса электронной почты перед @ с помощью регулярного выражения и возвращает ее. Вы заметили ошибку?
Давайте посмотрим, что происходит, когда мы используем pytype, чтобы проверить это:
% pytype get_username.py Analyzing 1 sources with 0 dependencies File "/.../get_username.py", line 5, in GetUsername: No attribute 'group' on None [attribute-error] In Optional[Match[str]]
Pytype говорит нам, что group не является допустимым вызовом функции при совпадении. re.match() возвращает None, если совпадений не найдено. Действительно, в этих случаях match.group(1) сгенерирует исключение.
Давайте исправим ошибку с помощью функции, возвращающей None для недействительного адреса электронной почты:
import re def GetUsername(email_address): match = re.match(r'([^@]+)@example\.com', email_address) if match is None: return None return match.group(1) # <-- Здесь match не может быть None
Теперь, когда мы повторно запускаем pytype, ошибка исчезла. Pytype подразумевает, что если код после if будет выполнен, match гарантированно не будет None.
Пример 2: проверка аннотаций типов
В Python 3 вы можете добавить статическую аннотацию типов (PEP 484) в свой код, чтобы помочь инструментам проверки типов и другим разработчикам понять ваше намерение. Pytype может предупреждать, когда ваши аннотации типов содержат ошибки:
import re from typing import Match def GetEmailMatch(email) -> Match: return re.match(r'([^@]+)@example\.com', email)
Давайте используем pytype, чтобы проверить этот фрагмент кода:
% pytype example.py Analyzing 1 sources with 0 dependencies File "/.../example.py", line 5, in GetEmailMatch: bad option in return type [bad-return-type] Expected: Match Actually returned: None
Pytype сообщает нам, что GetEmailMatch может вернуть None, но мы аннотировали его возвращаемый тип как Match. Чтобы исправить это, мы можем использовать опциональную аннотацию типа из модуля ввода:
import re from typing import Match, Optional def GetEmailMatch(email) -> Optional[Match]: return re.match(r'([^@]+)@example\.com', email)
Optional означает, что возвращаемое значение может быть объектом Match или None.
Пример 3: объединение информации о предполагаемом типе
Чтобы помочь вам установить аннотации типов, Pytype может добавить их в код для вас. Давайте посмотрим на этот фрагмент кода:
import re def GetEmailMatch(email): return re.match(r'([^@]+)@example\.com', email) def GetUsername(email_address): match = GetEmailMatch(email_address) if match is None: return None return match.group(1)
Чтобы добавить аннотации типов в этот код, мы сначала запускаем pytype для файла. pytype сохраняет информацию о предполагаемом типе в файл .pyi. Затем мы можем запустить merge-pyi, чтобы объединить аннотации типов обратно в код:
% pytype email.py % merge-pyi -i email.py pytype_output/email.pyi
И вуаля!
import re from typing import Match from typing import Optional def GetEmailMatch(email) -> Optional[Match[str]]: return re.match(r'([^@]+)@example\.com', email) def GetUsername(email_address) -> Optional[str]: match = GetEmailMatch(email_address) if match is None: return None return match.group(1)
Аннотации типов, включая операторы импорта, теперь находятся в исходном файле.
Дополнительные примеры использования и инструкции по установке, можно посмотреть GitHub.