committed by
GitHub
1 changed files with 448 additions and 0 deletions
@ -0,0 +1,448 @@ |
|||||
|
# Вступ до типів Python |
||||
|
|
||||
|
Python підтримує додаткові "підказки типу" ("type hints") (також звані "анотаціями типу" ("type annotations")). |
||||
|
|
||||
|
Ці **"type hints"** є спеціальним синтаксисом, що дозволяє оголошувати <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 |
||||
|
``` |
||||
|
|
||||
|
Ось і все. |
||||
|
|
||||
|
Це "type hints": |
||||
|
|
||||
|
```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`. І внутрішні значення також можуть мати свій тип. |
||||
|
|
||||
|
Ці типи, які мають внутрішні типи, називаються "**generic**" типами. І оголосити їх можна навіть із внутрішніми типами. |
||||
|
|
||||
|
Щоб оголосити ці типи та внутрішні типи, ви можете використовувати стандартний модуль Python `typing`. Він існує спеціально для підтримки анотацій типів. |
||||
|
|
||||
|
#### Новіші версії Python |
||||
|
|
||||
|
Синтаксис із використанням `typing` **сумісний** з усіма версіями, від Python 3.6 до останніх, включаючи Python 3.9, Python 3.10 тощо. |
||||
|
|
||||
|
У міру розвитку Python **новіші версії** мають покращену підтримку анотацій типів і в багатьох випадках вам навіть не потрібно буде імпортувати та використовувати модуль `typing` для оголошення анотацій типу. |
||||
|
|
||||
|
Якщо ви можете вибрати новішу версію Python для свого проекту, ви зможете скористатися цією додатковою простотою. Дивіться кілька прикладів нижче. |
||||
|
|
||||
|
#### List (список) |
||||
|
|
||||
|
Наприклад, давайте визначимо змінну, яка буде `list` із `str`. |
||||
|
|
||||
|
=== "Python 3.6 і вище" |
||||
|
|
||||
|
З модуля `typing`, імпортуємо `List` (з великої літери `L`): |
||||
|
|
||||
|
``` Python hl_lines="1" |
||||
|
{!> ../../../docs_src/python_types/tutorial006.py!} |
||||
|
``` |
||||
|
|
||||
|
Оголосимо змінну з тим самим синтаксисом двокрапки (`:`). |
||||
|
|
||||
|
Як тип вкажемо `List`, який ви імпортували з `typing`. |
||||
|
|
||||
|
Оскільки список є типом, який містить деякі внутрішні типи, ви поміщаєте їх у квадратні дужки: |
||||
|
|
||||
|
```Python hl_lines="4" |
||||
|
{!> ../../../docs_src/python_types/tutorial006.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.9 і вище" |
||||
|
|
||||
|
Оголосимо змінну з тим самим синтаксисом двокрапки (`:`). |
||||
|
|
||||
|
Як тип вкажемо `list`. |
||||
|
|
||||
|
Оскільки список є типом, який містить деякі внутрішні типи, ви поміщаєте їх у квадратні дужки: |
||||
|
|
||||
|
```Python hl_lines="1" |
||||
|
{!> ../../../docs_src/python_types/tutorial006_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
!!! info |
||||
|
Ці внутрішні типи в квадратних дужках називаються "параметрами типу". |
||||
|
|
||||
|
У цьому випадку, `str` це параметр типу переданий у `List` (або `list` у Python 3.9 і вище). |
||||
|
|
||||
|
Це означає: "змінна `items` це `list`, і кожен з елементів у цьому списку - `str`". |
||||
|
|
||||
|
!!! tip |
||||
|
Якщо ви використовуєте Python 3.9 і вище, вам не потрібно імпортувати `List` з `typing`, ви можете використовувати натомість тип `list`. |
||||
|
|
||||
|
Зробивши це, ваш редактор може надати підтримку навіть під час обробки елементів зі списку: |
||||
|
|
||||
|
<img src="/img/python-types/image05.png"> |
||||
|
|
||||
|
Без типів цього майже неможливо досягти. |
||||
|
|
||||
|
Зверніть увагу, що змінна `item` є одним із елементів у списку `items`. |
||||
|
|
||||
|
І все ж редактор знає, що це `str`, і надає підтримку для цього. |
||||
|
|
||||
|
#### Tuple and Set (кортеж та набір) |
||||
|
|
||||
|
Ви повинні зробити те ж саме, щоб оголосити `tuple` і `set`: |
||||
|
|
||||
|
=== "Python 3.6 і вище" |
||||
|
|
||||
|
```Python hl_lines="1 4" |
||||
|
{!> ../../../docs_src/python_types/tutorial007.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.9 і вище" |
||||
|
|
||||
|
```Python hl_lines="1" |
||||
|
{!> ../../../docs_src/python_types/tutorial007_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
Це означає: |
||||
|
|
||||
|
* Змінна `items_t` це `tuple` з 3 елементами, `int`, ще `int`, та `str`. |
||||
|
* Змінна `items_s` це `set`, і кожен його елемент типу `bytes`. |
||||
|
|
||||
|
#### Dict (словник) |
||||
|
|
||||
|
Щоб оголосити `dict`, вам потрібно передати 2 параметри типу, розділені комами. |
||||
|
|
||||
|
Перший параметр типу для ключа у `dict`. |
||||
|
|
||||
|
Другий параметр типу для значення у `dict`: |
||||
|
|
||||
|
=== "Python 3.6 і вище" |
||||
|
|
||||
|
```Python hl_lines="1 4" |
||||
|
{!> ../../../docs_src/python_types/tutorial008.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.9 і вище" |
||||
|
|
||||
|
```Python hl_lines="1" |
||||
|
{!> ../../../docs_src/python_types/tutorial008_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
Це означає: |
||||
|
|
||||
|
* Змінна `prices` це `dict`: |
||||
|
* Ключі цього `dict` типу `str` (наприклад, назва кожного елементу). |
||||
|
* Значення цього `dict` типу `float` (наприклад, ціна кожного елементу). |
||||
|
|
||||
|
#### Union (об'єднання) |
||||
|
|
||||
|
Ви можете оголосити, що змінна може бути будь-яким із **кількох типів**, наприклад, `int` або `str`. |
||||
|
|
||||
|
У Python 3.6 і вище (включаючи Python 3.10) ви можете використовувати тип `Union` з `typing` і вставляти в квадратні дужки можливі типи, які можна прийняти. |
||||
|
|
||||
|
У Python 3.10 також є **альтернативний синтаксис**, у якому ви можете розділити можливі типи за допомогою <abbr title='також називають «побітовим "або" оператором», але це значення тут не актуальне'>вертикальної смуги (`|`)</abbr>. |
||||
|
|
||||
|
=== "Python 3.6 і вище" |
||||
|
|
||||
|
```Python hl_lines="1 4" |
||||
|
{!> ../../../docs_src/python_types/tutorial008b.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.10 і вище" |
||||
|
|
||||
|
```Python hl_lines="1" |
||||
|
{!> ../../../docs_src/python_types/tutorial008b_py310.py!} |
||||
|
``` |
||||
|
|
||||
|
В обох випадках це означає, що `item` може бути `int` або `str`. |
||||
|
|
||||
|
#### Possibly `None` (Optional) |
||||
|
|
||||
|
Ви можете оголосити, що значення може мати тип, наприклад `str`, але також може бути `None`. |
||||
|
|
||||
|
У Python 3.6 і вище (включаючи Python 3.10) ви можете оголосити його, імпортувавши та використовуючи `Optional` з модуля `typing`. |
||||
|
|
||||
|
```Python hl_lines="1 4" |
||||
|
{!../../../docs_src/python_types/tutorial009.py!} |
||||
|
``` |
||||
|
|
||||
|
Використання `Optional[str]` замість просто `str` дозволить редактору допомогти вам виявити помилки, коли ви могли б вважати, що значенням завжди є `str`, хоча насправді воно також може бути `None`. |
||||
|
|
||||
|
`Optional[Something]` насправді є скороченням для `Union[Something, None]`, вони еквівалентні. |
||||
|
|
||||
|
Це також означає, що в Python 3.10 ви можете використовувати `Something | None`: |
||||
|
|
||||
|
=== "Python 3.6 і вище" |
||||
|
|
||||
|
```Python hl_lines="1 4" |
||||
|
{!> ../../../docs_src/python_types/tutorial009.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.6 і вище - альтернатива" |
||||
|
|
||||
|
```Python hl_lines="1 4" |
||||
|
{!> ../../../docs_src/python_types/tutorial009b.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.10 і вище" |
||||
|
|
||||
|
```Python hl_lines="1" |
||||
|
{!> ../../../docs_src/python_types/tutorial009_py310.py!} |
||||
|
``` |
||||
|
|
||||
|
#### Generic типи |
||||
|
|
||||
|
Ці типи, які приймають параметри типу у квадратних дужках, називаються **Generic types** or **Generics**, наприклад: |
||||
|
|
||||
|
=== "Python 3.6 і вище" |
||||
|
|
||||
|
* `List` |
||||
|
* `Tuple` |
||||
|
* `Set` |
||||
|
* `Dict` |
||||
|
* `Union` |
||||
|
* `Optional` |
||||
|
* ...та інші. |
||||
|
|
||||
|
=== "Python 3.9 і вище" |
||||
|
|
||||
|
Ви можете використовувати ті самі вбудовані типи, як generic (з квадратними дужками та типами всередині): |
||||
|
|
||||
|
* `list` |
||||
|
* `tuple` |
||||
|
* `set` |
||||
|
* `dict` |
||||
|
|
||||
|
І те саме, що й у Python 3.6, із модуля `typing`: |
||||
|
|
||||
|
* `Union` |
||||
|
* `Optional` |
||||
|
* ...та інші. |
||||
|
|
||||
|
=== "Python 3.10 і вище" |
||||
|
|
||||
|
Ви можете використовувати ті самі вбудовані типи, як generic (з квадратними дужками та типами всередині): |
||||
|
|
||||
|
* `list` |
||||
|
* `tuple` |
||||
|
* `set` |
||||
|
* `dict` |
||||
|
|
||||
|
І те саме, що й у Python 3.6, із модуля `typing`: |
||||
|
|
||||
|
* `Union` |
||||
|
* `Optional` (так само як у Python 3.6) |
||||
|
* ...та інші. |
||||
|
|
||||
|
У Python 3.10, як альтернатива використанню `Union` та `Optional`, ви можете використовувати <abbr title='також називають «побітовим "або" оператором», але це значення тут не актуальне'>вертикальну смугу (`|`)</abbr> щоб оголосити об'єднання типів. |
||||
|
|
||||
|
### Класи як типи |
||||
|
|
||||
|
Ви також можете оголосити клас як тип змінної. |
||||
|
|
||||
|
Скажімо, у вас є клас `Person` з імʼям: |
||||
|
|
||||
|
```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 3.6 і вище" |
||||
|
|
||||
|
```Python |
||||
|
{!> ../../../docs_src/python_types/tutorial011.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.9 і вище" |
||||
|
|
||||
|
```Python |
||||
|
{!> ../../../docs_src/python_types/tutorial011_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.10 і вище" |
||||
|
|
||||
|
```Python |
||||
|
{!> ../../../docs_src/python_types/tutorial011_py310.py!} |
||||
|
``` |
||||
|
|
||||
|
!!! info |
||||
|
Щоб дізнатись більше про <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic, перегляньте його документацію</a>. |
||||
|
|
||||
|
**FastAPI** повністю базується на Pydantic. |
||||
|
|
||||
|
Ви побачите набагато більше цього всього на практиці в [Tutorial - User Guide](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