Перейти к содержанию

Введение в типы Python

🌐 Перевод выполнен с помощью ИИ и людей

Этот перевод был сделан ИИ под руководством людей. 🤝

В нем могут быть ошибки из-за неправильного понимания оригинального смысла или неестественности и т. д. 🤖

Вы можете улучшить этот перевод, помогая нам лучше направлять ИИ LLM.

Английская версия

Python поддерживает необязательные «аннотации типов» (также называемые «подсказками типов»).

Эти «аннотации типов», или просто аннотации, — это специальный синтаксис, позволяющий объявлять тип переменной.

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

Это всего лишь краткое руководство / напоминание об аннотациях типов в Python. Оно охватывает только минимум, необходимый для их использования с FastAPI... что на самом деле очень мало.

FastAPI целиком основан на этих аннотациях типов — они дают ему множество преимуществ и выгод.

Но даже если вы никогда не используете FastAPI, вам будет полезно немного узнать о них.

Примечание

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

Мотивация

Давайте начнем с простого примера:

defget_full_name(first_name, last_name):
 full_name = first_name.title() + " " + last_name.title()
 return full_name
print(get_full_name("john", "doe"))

Вызов этой программы выводит:

John Doe

Функция делает следующее:

  • Принимает first_name и last_name.
  • Преобразует первую букву каждого значения в верхний регистр с помощью title().
  • Соединяет их пробелом посередине.
defget_full_name(first_name, last_name):
 full_name = first_name.title() + " " + last_name.title()
 return full_name
print(get_full_name("john", "doe"))

Отредактируем пример

Это очень простая программа.

А теперь представьте, что вы пишете её с нуля.

В какой-то момент вы бы начали определение функции, у вас были бы готовы параметры...

Но затем нужно вызвать «тот метод, который делает первую букву заглавной».

Это был upper? Или uppercase? first_uppercase? capitalize?

Тогда вы пробуете старого друга программиста — автозавершение редактора кода.

Вы вводите первый параметр функции, first_name, затем точку (.) и нажимаете Ctrl+Space, чтобы вызвать автозавершение.

Но, к сожалению, ничего полезного не находится:

Добавим типы

Давайте изменим одну строку из предыдущей версии.

Мы поменяем ровно этот фрагмент — параметры функции — с:

 first_name, last_name

на:

 first_name: str, last_name: str

Вот и всё.

Это и есть «аннотации типов»:

defget_full_name(first_name: str, last_name: str):
 full_name = first_name.title() + " " + last_name.title()
 return full_name
print(get_full_name("john", "doe"))

Это не то же самое, что объявление значений по умолчанию, как, например:

 first_name="john", last_name="doe"

Это другая вещь.

Здесь мы используем двоеточия (:), а не знак равенства (=).

И добавление аннотаций типов обычно не меняет поведение программы по сравнению с вариантом без них.

Но теперь представьте, что вы снова посередине написания этой функции, только уже с аннотациями типов.

В тот же момент вы пробуете вызвать автозавершение с помощью Ctrl+Space — и видите:

С этим вы можете прокручивать варианты, пока не найдёте тот самый:

Больше мотивации

Посмотрите на эту функцию — у неё уже есть аннотации типов:

defget_name_with_age(name: str, age: int):
 name_with_age = name + " is this old: " + age
 return name_with_age

Так как редактор кода знает типы переменных, вы получаете не только автозавершение, но и проверки ошибок:

Теперь вы знаете, что нужно исправить — преобразовать age в строку с помощью str(age):

defget_name_with_age(name: str, age: int):
 name_with_age = name + " is this old: " + str(age)
 return name_with_age

Объявление типов

Вы только что увидели основное место, где объявляют аннотации типов — параметры функции.

Это также основное место, где вы будете использовать их с FastAPI.

Простые типы

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

Можно использовать, например:

  • int
  • float
  • bool
  • bytes
defget_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):
 return item_a, item_b, item_c, item_d, item_e

Модуль typing

Для некоторых дополнительных сценариев может понадобиться импортировать что-то из стандартного модуля typing. Например, когда вы хотите объявить, что что-то имеет «любой тип», можно использовать Any из typing:

fromtypingimport Any
defsome_function(data: Any):
 print(data)

Generic-типы

Некоторые типы могут принимать «параметры типов» в квадратных скобках, чтобы определить их внутренние типы. Например, «список строк» объявляется как list[str].

Такие типы, которые принимают параметры типов, называются Generic-типами или Generics.

Вы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри):

  • list
  • tuple
  • set
  • dict

List

Например, давайте определим переменную как list из str.

Объявите переменную с тем же синтаксисом двоеточия (:).

В качестве типа укажите list.

Так как список — это тип, содержащий внутренние типы, укажите их в квадратных скобках:

defprocess_items(items: list[str]):
 for item in items:
 print(item)

Примечание

Эти внутренние типы в квадратных скобках называются «параметрами типов».

В данном случае str — это параметр типа, передаваемый в list.

Это означает: «переменная items — это list, и каждый элемент этого списка — str».

Таким образом, ваш редактор кода сможет помогать даже при обработке элементов списка:

Без типов добиться этого почти невозможно.

Обратите внимание, что переменная item — один из элементов списка items.

И всё же редактор кода знает, что это str, и даёт соответствующую поддержку.

Tuple и Set

Аналогично вы бы объявили tuple и set:

defprocess_items(items_t: tuple[int, int, str], items_s: set[bytes]):
 return items_t, items_s

Это означает:

  • Переменная items_t — это tuple из 3 элементов: int, ещё один int и str.
  • Переменная items_s — это set, и каждый элемент имеет тип bytes.

Dict

Чтобы определить dict, вы передаёте 2 параметра типов, разделённые запятой.

Первый параметр типа — для ключей dict.

Второй параметр типа — для значений dict:

defprocess_items(prices: dict[str, float]):
 for item_name, item_price in prices.items():
 print(item_name)
 print(item_price)

Это означает:

  • Переменная prices — это dict:
    • Ключи этого dict имеют тип str (скажем, название каждой позиции).
    • Значения этого dict имеют тип float (скажем, цена каждой позиции).

Union

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

Чтобы это определить, используйте вертикальную черту (|) для разделения обоих типов.

Это называется «объединение» (union), потому что переменная может быть чем угодно из объединения этих двух множеств типов.

defprocess_item(item: int | str):
 print(item)

Это означает, что item может быть int или str.

Возможно None

Вы можете объявить, что значение может иметь определённый тип, например str, но также может быть и None.

defsay_hi(name: str | None = None):
 if name is not None:
 print(f"Hey {name}!")
 else:
 print("Hello World")

Использование str | None вместо просто str позволит редактору кода помочь вам обнаружить ошибки, когда вы предполагаете, что значение всегда str, хотя на самом деле оно может быть и None.

Классы как типы

Вы также можете объявлять класс как тип переменной.

Допустим, у вас есть класс Person с именем:

classPerson:
 def__init__(self, name: str):
 self.name = name
defget_person_name(one_person: Person):
 return one_person.name

Тогда вы можете объявить переменную типа Person:

classPerson:
 def__init__(self, name: str):
 self.name = name
defget_person_name(one_person: Person):
 return one_person.name

И снова вы получите полную поддержку редактора кода:

Обратите внимание, что это означает: «one_person — это экземпляр класса Person».

Это не означает: «one_person — это класс с именем Person».

Pydantic-модели

Pydantic — это библиотека Python для валидации данных.

Вы объявляете «форму» данных как классы с атрибутами.

И у каждого атрибута есть тип.

Затем вы создаёте экземпляр этого класса с некоторыми значениями — он провалидирует значения, преобразует их к соответствующему типу (если это применимо) и вернёт вам объект со всеми данными.

И вы получите полную поддержку редактора кода для этого результирующего объекта.

Пример из официальной документации Pydantic:

fromdatetimeimport datetime
frompydanticimport BaseModel
classUser(BaseModel):
 id: int
 name: str = "John Doe"
 signup_ts: datetime | None = None
 friends: list[int] = []
external_data = {
 "id": "123",
 "signup_ts": "2017年06月01日 12:22",
 "friends": [1, "2", b"3"],
}
user = User(**external_data)
print(user)
# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
print(user.id)
# > 123

Примечание

Чтобы узнать больше о Pydantic, ознакомьтесь с его документацией.

FastAPI целиком основан на Pydantic.

Вы увидите намного больше всего этого на практике в Учебник - Руководство пользователя.

Аннотации типов с аннотациями метаданных

В Python также есть возможность добавлять дополнительные метаданные к аннотациям типов с помощью Annotated.

Вы можете импортировать Annotated из typing.

fromtypingimport Annotated
defsay_hello(name: Annotated[str, "this is just metadata"]) -> str:
 return f"Hello {name}"

Сам Python ничего не делает с Annotated. А для редакторов кода и других инструментов тип по-прежнему str.

Но вы можете использовать это место в Annotated, чтобы передать FastAPI дополнительные метаданные о том, как вы хотите, чтобы ваше приложение себя вело.

Важно помнить, что первый параметр типа, который вы передаёте в Annotated, — это фактический тип. Всё остальное — просто метаданные для других инструментов.

Пока вам достаточно знать, что Annotated существует и это — стандартный Python. 😎

Позже вы увидите, насколько это мощно.

Совет

Тот факт, что это стандартный Python, означает, что вы по-прежнему получите лучший возможный разработческий опыт в вашем редакторе кода, с инструментами для анализа и рефакторинга кода и т.д. ✨

А ещё ваш код будет очень совместим со множеством других инструментов и библиотек Python. 🚀

Аннотации типов в FastAPI

FastAPI использует эти аннотации типов для выполнения нескольких задач.

С FastAPI вы объявляете параметры с аннотациями типов и получаете:

  • Поддержку редактора кода.
  • Проверки типов.

...и FastAPI использует эти же объявления для:

  • Определения требований: из path-параметров HTTP-запроса, query-параметров, HTTP-заголовков, тел запросов, зависимостей и т.д.
  • Преобразования данных: из HTTP-запроса к требуемому типу.
  • Валидации данных: приходящих с каждого HTTP-запроса:
    • Генерации автоматических ошибок, возвращаемых клиенту, когда данные некорректны.
  • Документирования API с использованием OpenAPI:
    • что затем используется пользовательскими интерфейсами автоматической интерактивной документации.

Всё это может звучать абстрактно. Не волнуйтесь. Вы увидите всё это в действии в Учебник - Руководство пользователя.

Важно то, что, используя стандартные типы Python в одном месте (вместо добавления дополнительных классов, декораторов и т.д.), FastAPI сделает за вас большую часть работы.

Примечание

Если вы уже прошли всё руководство и вернулись, чтобы узнать больше о типах, хорошим ресурсом будет «шпаргалка» от mypy.

AltStyle によって変換されたページ (->オリジナル) /