committed by
GitHub
1 changed files with 314 additions and 0 deletions
@ -0,0 +1,314 @@ |
|||||
|
# Введение в аннотации типов Python |
||||
|
|
||||
|
Python имеет поддержку необязательных аннотаций типов. |
||||
|
|
||||
|
**Аннотации типов** являются специальным синтаксисом, который позволяет определять <abbr title="например: str, int, float, bool">тип</abbr> переменной. |
||||
|
|
||||
|
Объявление типов для переменных позволяет улучшить поддержку вашего кода редакторами и различными инструментами. |
||||
|
|
||||
|
Это просто **краткое руководство / напоминание** об аннотациях типов в Python. Оно охватывает только минимум, необходимый для их использования с **FastAPI**... что на самом деле очень мало. |
||||
|
|
||||
|
**FastAPI** целиком основан на аннотациях типов, у них много выгод и преимуществ. |
||||
|
|
||||
|
Но даже если вы никогда не используете **FastAPI**, вам будет полезно немного узнать о них. |
||||
|
|
||||
|
!!! note |
||||
|
Если вы являетесь экспертом в Python и уже знаете всё об аннотациях типов, переходите к следующему разделу. |
||||
|
|
||||
|
## Мотивация |
||||
|
|
||||
|
Давайте начнем с простого примера: |
||||
|
|
||||
|
```Python |
||||
|
{!../../../docs_src/python_types/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
Вызов этой программы выводит: |
||||
|
|
||||
|
``` |
||||
|
John Doe |
||||
|
``` |
||||
|
|
||||
|
Функция делает следующее: |
||||
|
|
||||
|
* Принимает `first_name` и `last_name`. |
||||
|
* Преобразует первую букву содержимого каждой переменной в верхний регистр с `title()`. |
||||
|
* <abbr title="Объединяет в одно целое, последовательно, друг за другом.">Соединяет</abbr> их через пробел. |
||||
|
|
||||
|
```Python hl_lines="2" |
||||
|
{!../../../docs_src/python_types/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Отредактируем пример |
||||
|
|
||||
|
Это очень простая программа. |
||||
|
|
||||
|
А теперь представьте, что вы пишете её с нуля. |
||||
|
|
||||
|
В какой-то момент вы бы начали определение функции, у вас были бы готовы параметры... |
||||
|
|
||||
|
Но затем вы должны вызвать «тот метод, который преобразует первую букву в верхний регистр». |
||||
|
|
||||
|
Было это `upper`? Или `uppercase`? `first_uppercase`? `capitalize`? |
||||
|
|
||||
|
Тогда вы попробуете с давним другом программиста: автодополнением редактора. |
||||
|
|
||||
|
Вы вводите первый параметр функции, `first_name`, затем точку (`.`), а затем нажимаете `Ctrl+Space`, чтобы запустить дополнение. |
||||
|
|
||||
|
Но, к сожалению, ничего полезного не выходит: |
||||
|
|
||||
|
<img src="/img/python-types/image01.png"> |
||||
|
|
||||
|
### Добавим типы |
||||
|
|
||||
|
Давайте изменим одну строчку в предыдущей версии. |
||||
|
|
||||
|
Мы изменим именно этот фрагмент, параметры функции, с: |
||||
|
|
||||
|
```Python |
||||
|
first_name, last_name |
||||
|
``` |
||||
|
|
||||
|
на: |
||||
|
|
||||
|
```Python |
||||
|
first_name: str, last_name: str |
||||
|
``` |
||||
|
|
||||
|
Вот и все. |
||||
|
|
||||
|
Это аннотации типов: |
||||
|
|
||||
|
```Python hl_lines="1" |
||||
|
{!../../../docs_src/python_types/tutorial002.py!} |
||||
|
``` |
||||
|
|
||||
|
Это не то же самое, что объявление значений по умолчанию, например: |
||||
|
|
||||
|
```Python |
||||
|
first_name="john", last_name="doe" |
||||
|
``` |
||||
|
|
||||
|
Это другая вещь. |
||||
|
|
||||
|
Мы используем двоеточия (`:`), а не равно (`=`). |
||||
|
|
||||
|
И добавление аннотаций типов обычно не меняет происходящего по сравнению с тем, что произошло бы без неё. |
||||
|
|
||||
|
Но теперь представьте, что вы снова находитесь в процессе создания этой функции, но уже с аннотациями типов. |
||||
|
|
||||
|
В тот же момент вы пытаетесь запустить автодополнение с помощью `Ctrl+Space` и вы видите: |
||||
|
|
||||
|
<img src="/img/python-types/image02.png"> |
||||
|
|
||||
|
При этом вы можете просматривать варианты, пока не найдёте подходящий: |
||||
|
|
||||
|
<img src="/img/python-types/image03.png"> |
||||
|
|
||||
|
## Больше мотивации |
||||
|
|
||||
|
Проверьте эту функцию, она уже имеет аннотации типов: |
||||
|
|
||||
|
```Python hl_lines="1" |
||||
|
{!../../../docs_src/python_types/tutorial003.py!} |
||||
|
``` |
||||
|
|
||||
|
Поскольку редактор знает типы переменных, вы получаете не только дополнение, но и проверки ошибок: |
||||
|
|
||||
|
<img src="/img/python-types/image04.png"> |
||||
|
|
||||
|
Теперь вы знаете, что вам нужно исправить, преобразовав `age` в строку с `str(age)`: |
||||
|
|
||||
|
```Python hl_lines="2" |
||||
|
{!../../../docs_src/python_types/tutorial004.py!} |
||||
|
``` |
||||
|
|
||||
|
## Объявление типов |
||||
|
|
||||
|
Вы только что видели основное место для объявления подсказок типов. В качестве параметров функции. |
||||
|
|
||||
|
Это также основное место, где вы можете использовать их с **FastAPI**. |
||||
|
|
||||
|
### Простые типы |
||||
|
|
||||
|
Вы можете объявить все стандартные типы Python, а не только `str`. |
||||
|
|
||||
|
Вы можете использовать, к примеру: |
||||
|
|
||||
|
* `int` |
||||
|
* `float` |
||||
|
* `bool` |
||||
|
* `bytes` |
||||
|
|
||||
|
```Python hl_lines="1" |
||||
|
{!../../../docs_src/python_types/tutorial005.py!} |
||||
|
``` |
||||
|
|
||||
|
### Generic-типы с параметрами типов |
||||
|
|
||||
|
Существуют некоторые структуры данных, которые могут содержать другие значения, например, `dict`, `list`, `set` и `tuple`. И внутренние значения тоже могут иметь свой тип. |
||||
|
|
||||
|
Чтобы объявить эти типы и внутренние типы, вы можете использовать стандартный Python-модуль `typing`. |
||||
|
|
||||
|
Он существует специально для поддержки подсказок этих типов. |
||||
|
|
||||
|
#### `List` |
||||
|
|
||||
|
Например, давайте определим переменную как `list`, состоящий из `str`. |
||||
|
|
||||
|
Импортируйте `List` из `typing` (с заглавной `L`): |
||||
|
|
||||
|
```Python hl_lines="1" |
||||
|
{!../../../docs_src/python_types/tutorial006.py!} |
||||
|
``` |
||||
|
|
||||
|
Объявите переменную с тем же синтаксисом двоеточия (`:`). |
||||
|
|
||||
|
В качестве типа укажите `List`. |
||||
|
|
||||
|
Поскольку список является типом, содержащим некоторые внутренние типы, вы помещаете их в квадратные скобки: |
||||
|
|
||||
|
```Python hl_lines="4" |
||||
|
{!../../../docs_src/python_types/tutorial006.py!} |
||||
|
``` |
||||
|
|
||||
|
!!! tip |
||||
|
Эти внутренние типы в квадратных скобках называются «параметрами типов». |
||||
|
|
||||
|
В этом случае `str` является параметром типа, передаваемым в `List`. |
||||
|
|
||||
|
Это означает: "переменная `items` является `list`, и каждый из элементов этого списка является `str`". |
||||
|
|
||||
|
Если вы будете так поступать, редактор может оказывать поддержку даже при обработке элементов списка: |
||||
|
|
||||
|
<img src="/img/python-types/image05.png"> |
||||
|
|
||||
|
Без типов добиться этого практически невозможно. |
||||
|
|
||||
|
Обратите внимание, что переменная `item` является одним из элементов списка `items`. |
||||
|
|
||||
|
И все же редактор знает, что это `str`, и поддерживает это. |
||||
|
|
||||
|
#### `Tuple` и `Set` |
||||
|
|
||||
|
Вы бы сделали то же самое, чтобы объявить `tuple` и `set`: |
||||
|
|
||||
|
```Python hl_lines="1 4" |
||||
|
{!../../../docs_src/python_types/tutorial007.py!} |
||||
|
``` |
||||
|
|
||||
|
Это означает: |
||||
|
|
||||
|
* Переменная `items_t` является `tuple` с 3 элементами: `int`, другим `int` и `str`. |
||||
|
* Переменная `items_s` является `set` и каждый элемент имеет тип `bytes`. |
||||
|
|
||||
|
#### `Dict` |
||||
|
|
||||
|
Чтобы определить `dict`, вы передаёте 2 параметра типов, разделённых запятыми. |
||||
|
|
||||
|
Первый параметр типа предназначен для ключей `dict`. |
||||
|
|
||||
|
Второй параметр типа предназначен для значений `dict`: |
||||
|
|
||||
|
```Python hl_lines="1 4" |
||||
|
{!../../../docs_src/python_types/tutorial008.py!} |
||||
|
``` |
||||
|
|
||||
|
Это означает: |
||||
|
|
||||
|
* Переменная `prices` является `dict`: |
||||
|
* Ключи этого `dict` имеют тип `str` (скажем, название каждого элемента). |
||||
|
* Значения этого `dict` имеют тип `float` (скажем, цена каждой позиции). |
||||
|
|
||||
|
#### `Optional` |
||||
|
|
||||
|
Вы также можете использовать `Optional`, чтобы объявить, что переменная имеет тип, например, `str`, но это является «необязательным», что означает, что она также может быть `None`: |
||||
|
|
||||
|
```Python hl_lines="1 4" |
||||
|
{!../../../docs_src/python_types/tutorial009.py!} |
||||
|
``` |
||||
|
|
||||
|
Использование `Optional[str]` вместо просто `str` позволит редактору помочь вам в обнаружении ошибок, в которых вы могли бы предположить, что значение всегда является `str`, хотя на самом деле это может быть и `None`. |
||||
|
|
||||
|
#### Generic-типы |
||||
|
|
||||
|
Эти типы принимают параметры в квадратных скобках: |
||||
|
|
||||
|
* `List` |
||||
|
* `Tuple` |
||||
|
* `Set` |
||||
|
* `Dict` |
||||
|
* `Optional` |
||||
|
* ...и др. |
||||
|
|
||||
|
называются **Generic-типами** или **Generics**. |
||||
|
|
||||
|
### Классы как типы |
||||
|
|
||||
|
Вы также можете объявить класс как тип переменной. |
||||
|
|
||||
|
Допустим, у вас есть класс `Person` с полем `name`: |
||||
|
|
||||
|
```Python hl_lines="1-3" |
||||
|
{!../../../docs_src/python_types/tutorial010.py!} |
||||
|
``` |
||||
|
|
||||
|
Тогда вы можете объявить переменную типа `Person`: |
||||
|
|
||||
|
```Python hl_lines="6" |
||||
|
{!../../../docs_src/python_types/tutorial010.py!} |
||||
|
``` |
||||
|
|
||||
|
И снова вы получаете полную поддержку редактора: |
||||
|
|
||||
|
<img src="/img/python-types/image06.png"> |
||||
|
|
||||
|
## Pydantic-модели |
||||
|
|
||||
|
<a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> является Python-библиотекой для выполнения валидации данных. |
||||
|
|
||||
|
Вы объявляете «форму» данных как классы с атрибутами. |
||||
|
|
||||
|
И каждый атрибут имеет тип. |
||||
|
|
||||
|
Затем вы создаете экземпляр этого класса с некоторыми значениями, и он проверяет значения, преобразует их в соответствующий тип (если все верно) и предоставляет вам объект со всеми данными. |
||||
|
|
||||
|
И вы получаете полную поддержку редактора для этого итогового объекта. |
||||
|
|
||||
|
Взято из официальной документации Pydantic: |
||||
|
|
||||
|
```Python |
||||
|
{!../../../docs_src/python_types/tutorial011.py!} |
||||
|
``` |
||||
|
|
||||
|
!!! info |
||||
|
Чтобы узнать больше о <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic, читайте его документацию</a>. |
||||
|
|
||||
|
**FastAPI** целиком основан на Pydantic. |
||||
|
|
||||
|
Вы увидите намного больше всего этого на практике в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}. |
||||
|
|
||||
|
## Аннотации типов в **FastAPI** |
||||
|
|
||||
|
**FastAPI** получает преимущества аннотаций типов для выполнения определённых задач. |
||||
|
|
||||
|
С **FastAPI** вы объявляете параметры с аннотациями типов и получаете: |
||||
|
|
||||
|
* **Поддержку редактора**. |
||||
|
* **Проверки типов**. |
||||
|
|
||||
|
...и **FastAPI** использует тот же механизм для: |
||||
|
|
||||
|
* **Определения требований**: из параметров пути запроса, параметров запроса, заголовков, зависимостей и т.д. |
||||
|
* **Преобразования данных**: от запроса к нужному типу. |
||||
|
* **Валидации данных**: исходя из каждого запроса: |
||||
|
* Генерации **автоматических ошибок**, возвращаемых клиенту, когда данные не являются корректными. |
||||
|
* **Документирования** API с использованием OpenAPI: |
||||
|
* который затем используется пользовательскими интерфейсами автоматической интерактивной документации. |
||||
|
|
||||
|
Всё это может показаться абстрактным. Не волнуйтесь. Вы увидите всё это в действии в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}. |
||||
|
|
||||
|
Важно то, что при использовании стандартных типов Python в одном месте (вместо добавления дополнительных классов, декораторов и т.д.) **FastAPI** сделает за вас большую часть работы. |
||||
|
|
||||
|
!!! info |
||||
|
Если вы уже прошли всё руководство и вернулись, чтобы узнать больше о типах, хорошим ресурсом является <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">«шпаргалка» от `mypy`</a>. |
Loading…
Reference in new issue