committed by
GitHub
1 changed files with 478 additions and 0 deletions
@ -0,0 +1,478 @@ |
|||
# Классы как зависимости |
|||
|
|||
Прежде чем углубиться в систему **Внедрения Зависимостей**, давайте обновим предыдущий пример. |
|||
|
|||
## `Словарь` из предыдущего примера |
|||
|
|||
В предыдущем примере мы возвращали `словарь` из нашей зависимости: |
|||
|
|||
=== "Python 3.10+" |
|||
|
|||
```Python hl_lines="9" |
|||
{!> ../../../docs_src/dependencies/tutorial001_an_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.9+" |
|||
|
|||
```Python hl_lines="11" |
|||
{!> ../../../docs_src/dependencies/tutorial001_an_py39.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python hl_lines="12" |
|||
{!> ../../../docs_src/dependencies/tutorial001_an.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="7" |
|||
{!> ../../../docs_src/dependencies/tutorial001_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="11" |
|||
{!> ../../../docs_src/dependencies/tutorial001.py!} |
|||
``` |
|||
|
|||
Но затем мы получаем `словарь` в параметре `commons` *функции операции пути*. И мы знаем, что редакторы не могут обеспечить достаточную поддержку для `словаря`, поскольку они не могут знать их ключи и типы значений. |
|||
|
|||
Мы можем сделать лучше... |
|||
|
|||
## Что делает зависимость |
|||
|
|||
До сих пор вы видели зависимости, объявленные как функции. |
|||
|
|||
Но это не единственный способ объявления зависимостей (хотя, вероятно, более распространенный). |
|||
|
|||
Ключевым фактором является то, что зависимость должна быть "вызываемой". |
|||
|
|||
В Python "**вызываемый**" - это все, что Python может "вызвать", как функцию. |
|||
|
|||
Так, если у вас есть объект `something` (который может _не_ быть функцией) и вы можете "вызвать" его (выполнить) как: |
|||
|
|||
```Python |
|||
something() |
|||
``` |
|||
|
|||
или |
|||
|
|||
```Python |
|||
something(some_argument, some_keyword_argument="foo") |
|||
``` |
|||
|
|||
в таком случае он является "вызываемым". |
|||
|
|||
## Классы как зависимости |
|||
|
|||
Вы можете заметить, что для создания экземпляра класса в Python используется тот же синтаксис. |
|||
|
|||
Например: |
|||
|
|||
```Python |
|||
class Cat: |
|||
def __init__(self, name: str): |
|||
self.name = name |
|||
|
|||
|
|||
fluffy = Cat(name="Mr Fluffy") |
|||
``` |
|||
|
|||
В данном случае `fluffy` является экземпляром класса `Cat`. |
|||
|
|||
А чтобы создать `fluffy`, вы "вызываете" `Cat`. |
|||
|
|||
Таким образом, класс в Python также является **вызываемым**. |
|||
|
|||
Тогда в **FastAPI** в качестве зависимости можно использовать класс Python. |
|||
|
|||
На самом деле FastAPI проверяет, что переданный объект является "вызываемым" (функция, класс или что-либо еще) и указаны необходимые для его вызова параметры. |
|||
|
|||
Если вы передаёте что-то, что можно "вызывать" в качестве зависимости в **FastAPI**, то он будет анализировать параметры, необходимые для "вызова" этого объекта и обрабатывать их так же, как параметры *функции операции пути*. Включая подзависимости. |
|||
|
|||
Это относится и к вызываемым объектам без параметров. Работа с ними происходит точно так же, как и для *функций операции пути* без параметров. |
|||
|
|||
Теперь мы можем изменить зависимость `common_parameters`, указанную выше, на класс `CommonQueryParams`: |
|||
|
|||
=== "Python 3.10+" |
|||
|
|||
```Python hl_lines="11-15" |
|||
{!> ../../../docs_src/dependencies/tutorial002_an_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.9+" |
|||
|
|||
```Python hl_lines="11-15" |
|||
{!> ../../../docs_src/dependencies/tutorial002_an_py39.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python hl_lines="12-16" |
|||
{!> ../../../docs_src/dependencies/tutorial002_an.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="9-13" |
|||
{!> ../../../docs_src/dependencies/tutorial002_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="11-15" |
|||
{!> ../../../docs_src/dependencies/tutorial002.py!} |
|||
``` |
|||
|
|||
Обратите внимание на метод `__init__`, используемый для создания экземпляра класса: |
|||
|
|||
=== "Python 3.10+" |
|||
|
|||
```Python hl_lines="12" |
|||
{!> ../../../docs_src/dependencies/tutorial002_an_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.9+" |
|||
|
|||
```Python hl_lines="12" |
|||
{!> ../../../docs_src/dependencies/tutorial002_an_py39.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python hl_lines="13" |
|||
{!> ../../../docs_src/dependencies/tutorial002_an.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="10" |
|||
{!> ../../../docs_src/dependencies/tutorial002_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="12" |
|||
{!> ../../../docs_src/dependencies/tutorial002.py!} |
|||
``` |
|||
|
|||
...имеет те же параметры, что и ранее используемая функция `common_parameters`: |
|||
|
|||
=== "Python 3.10+" |
|||
|
|||
```Python hl_lines="8" |
|||
{!> ../../../docs_src/dependencies/tutorial001_an_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.9+" |
|||
|
|||
```Python hl_lines="9" |
|||
{!> ../../../docs_src/dependencies/tutorial001_an_py39.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python hl_lines="10" |
|||
{!> ../../../docs_src/dependencies/tutorial001_an.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="6" |
|||
{!> ../../../docs_src/dependencies/tutorial001_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="9" |
|||
{!> ../../../docs_src/dependencies/tutorial001.py!} |
|||
``` |
|||
|
|||
Эти параметры и будут использоваться **FastAPI** для "решения" зависимости. |
|||
|
|||
В обоих случаях она будет иметь: |
|||
|
|||
* Необязательный параметр запроса `q`, представляющий собой `str`. |
|||
* Параметр запроса `skip`, представляющий собой `int`, по умолчанию `0`. |
|||
* Параметр запроса `limit`, представляющий собой `int`, по умолчанию равный `100`. |
|||
|
|||
В обоих случаях данные будут конвертированы, валидированы, документированы по схеме OpenAPI и т.д. |
|||
|
|||
## Как это использовать |
|||
|
|||
Теперь вы можете объявить свою зависимость, используя этот класс. |
|||
|
|||
=== "Python 3.10+" |
|||
|
|||
```Python hl_lines="19" |
|||
{!> ../../../docs_src/dependencies/tutorial002_an_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.9+" |
|||
|
|||
```Python hl_lines="19" |
|||
{!> ../../../docs_src/dependencies/tutorial002_an_py39.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python hl_lines="20" |
|||
{!> ../../../docs_src/dependencies/tutorial002_an.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="17" |
|||
{!> ../../../docs_src/dependencies/tutorial002_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="19" |
|||
{!> ../../../docs_src/dependencies/tutorial002.py!} |
|||
``` |
|||
|
|||
**FastAPI** вызывает класс `CommonQueryParams`. При этом создается "экземпляр" этого класса, который будет передан в качестве параметра `commons` в вашу функцию. |
|||
|
|||
## Аннотация типа или `Depends` |
|||
|
|||
Обратите внимание, что в приведенном выше коде мы два раза пишем `CommonQueryParams`: |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python |
|||
commons: CommonQueryParams = Depends(CommonQueryParams) |
|||
``` |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python |
|||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] |
|||
``` |
|||
|
|||
Последний параметр `CommonQueryParams`, в: |
|||
|
|||
```Python |
|||
... Depends(CommonQueryParams) |
|||
``` |
|||
|
|||
...это то, что **FastAPI** будет использовать, чтобы узнать, что является зависимостью. |
|||
|
|||
Из него FastAPI извлечёт объявленные параметры и именно их будет вызывать. |
|||
|
|||
--- |
|||
|
|||
В этом случае первый `CommonQueryParams`, в: |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python |
|||
commons: Annotated[CommonQueryParams, ... |
|||
``` |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python |
|||
commons: CommonQueryParams ... |
|||
``` |
|||
|
|||
...не имеет никакого специального значения для **FastAPI**. FastAPI не будет использовать его для преобразования данных, валидации и т.д. (поскольку для этого используется `Depends(CommonQueryParams)`). |
|||
|
|||
На самом деле можно написать просто: |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python |
|||
commons: Annotated[Any, Depends(CommonQueryParams)] |
|||
``` |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python |
|||
commons = Depends(CommonQueryParams) |
|||
``` |
|||
|
|||
...как тут: |
|||
|
|||
=== "Python 3.10+" |
|||
|
|||
```Python hl_lines="19" |
|||
{!> ../../../docs_src/dependencies/tutorial003_an_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.9+" |
|||
|
|||
```Python hl_lines="19" |
|||
{!> ../../../docs_src/dependencies/tutorial003_an_py39.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python hl_lines="20" |
|||
{!> ../../../docs_src/dependencies/tutorial003_an.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="17" |
|||
{!> ../../../docs_src/dependencies/tutorial003_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="19" |
|||
{!> ../../../docs_src/dependencies/tutorial003.py!} |
|||
``` |
|||
|
|||
Но объявление типа приветствуется, так как в этом случае ваш редактор будет знать, что будет передано в качестве параметра `commons`, и тогда он сможет помочь вам с автодополнением, проверкой типов и т.д: |
|||
|
|||
<img src="/img/tutorial/dependencies/image02.png"> |
|||
|
|||
## Сокращение |
|||
|
|||
Но вы видите, что здесь мы имеем некоторое повторение кода, дважды написав `CommonQueryParams`: |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python |
|||
commons: CommonQueryParams = Depends(CommonQueryParams) |
|||
``` |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python |
|||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] |
|||
``` |
|||
|
|||
Для случаев, когда зависимостью является *конкретный* класс, который **FastAPI** "вызовет" для создания экземпляра этого класса, можно использовать укороченную запись. |
|||
|
|||
|
|||
Вместо того чтобы писать: |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python |
|||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] |
|||
``` |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python |
|||
commons: CommonQueryParams = Depends(CommonQueryParams) |
|||
``` |
|||
|
|||
...следует написать: |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python |
|||
commons: Annotated[CommonQueryParams, Depends()] |
|||
``` |
|||
|
|||
=== "Python 3.6 без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python |
|||
commons: CommonQueryParams = Depends() |
|||
``` |
|||
|
|||
Вы объявляете зависимость как тип параметра и используете `Depends()` без какого-либо параметра, вместо того чтобы *снова* писать полный класс внутри `Depends(CommonQueryParams)`. |
|||
|
|||
Аналогичный пример будет выглядеть следующим образом: |
|||
|
|||
=== "Python 3.10+" |
|||
|
|||
```Python hl_lines="19" |
|||
{!> ../../../docs_src/dependencies/tutorial004_an_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.9+" |
|||
|
|||
```Python hl_lines="19" |
|||
{!> ../../../docs_src/dependencies/tutorial004_an_py39.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+" |
|||
|
|||
```Python hl_lines="20" |
|||
{!> ../../../docs_src/dependencies/tutorial004_an.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="17" |
|||
{!> ../../../docs_src/dependencies/tutorial004_py310.py!} |
|||
``` |
|||
|
|||
=== "Python 3.6+ без Annotated" |
|||
|
|||
!!! tip "Подсказка" |
|||
Рекомендуется использовать версию с `Annotated` если возможно. |
|||
|
|||
```Python hl_lines="19" |
|||
{!> ../../../docs_src/dependencies/tutorial004.py!} |
|||
``` |
|||
|
|||
...и **FastAPI** будет знать, что делать. |
|||
|
|||
!!! tip "Подсказка" |
|||
Если это покажется вам более запутанным, чем полезным, не обращайте внимания, это вам не *нужно*. |
|||
|
|||
Это просто сокращение. Потому что **FastAPI** заботится о том, чтобы помочь вам свести к минимуму повторение кода. |
Loading…
Reference in new issue