DevGang
Авторизоваться

Как быстро найти проблемы с типами в вашем коде 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.

#Python
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

Поделитесь своим опытом, расскажите о новом инструменте, библиотеке или фреймворке. Для этого не обязательно становится постоянным автором.

Попробовать

В этом месте могла бы быть ваша реклама

Разместить рекламу