# Классы как зависимости

Прежде чем углубиться в систему **Внедрения Зависимостей**, давайте обновим предыдущий пример.

## `Словарь` из предыдущего примера

В предыдущем примере мы возвращали `словарь` из нашей зависимости:

=== "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** заботится о том, чтобы помочь вам свести к минимуму повторение кода.
