# Просунуті залежності { #advanced-dependencies }

## Параметризовані залежності { #parameterized-dependencies }

Усі залежності, які ми бачили, - це фіксована функція або клас.

Але можуть бути випадки, коли ви хочете мати змогу задавати параметри залежності, не оголошуючи багато різних функцій або класів.

Уявімо, що ми хочемо мати залежність, яка перевіряє, чи параметр запиту `q` містить певний фіксований вміст.

Але ми хочемо мати змогу параметризувати цей фіксований вміст.

## Екземпляр «callable» { #a-callable-instance }

У Python є спосіб зробити екземпляр класу «callable».

Не сам клас (який уже є «callable»), а екземпляр цього класу.

Щоб це зробити, оголошуємо метод `__call__`:

{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}

У цьому випадку саме `__call__` **FastAPI** використає для перевірки додаткових параметрів і підзалежностей, і саме його буде викликано, щоб передати значення параметру у вашу *функцію операції шляху* пізніше.

## Параметризувати екземпляр { #parameterize-the-instance }

Тепер ми можемо використати `__init__`, щоб оголосити параметри екземпляра, які можна застосувати для «параметризації» залежності:

{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}

У цьому випадку **FastAPI** ніколи не торкається `__init__` і не покладається на нього - ми використовуватимемо його безпосередньо у своєму коді.

## Створити екземпляр { #create-an-instance }

Ми можемо створити екземпляр цього класу так:

{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}

Таким чином ми «параметризуємо» нашу залежність, яка тепер містить «bar» як атрибут `checker.fixed_content`.

## Використовувати екземпляр як залежність { #use-the-instance-as-a-dependency }

Далі ми можемо використати цей `checker` у `Depends(checker)` замість `Depends(FixedContentQueryChecker)`, адже залежністю є екземпляр `checker`, а не сам клас.

Коли залежність розв'язується, **FastAPI** викличе цей `checker` так:

```Python
checker(q="somequery")
```

...і передасть усе, що він поверне, як значення залежності у нашій *функції операції шляху* як параметр `fixed_content_included`:

{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}

/// tip

Усе це може здаватися надуманим. І поки що може бути не дуже зрозуміло, навіщо це корисно.

Ці приклади навмисно прості, але показують, як усе працює.

У розділах про безпеку є утилітарні функції, реалізовані таким самим способом.

Якщо ви все це зрозуміли, ви вже знаєте, як під капотом працюють ті утиліти для безпеки.

///

## Залежності з `yield`, `HTTPException`, `except` та фоновими задачами { #dependencies-with-yield-httpexception-except-and-background-tasks }

/// warning

Найімовірніше, вам не знадобляться ці технічні деталі.

Вони корисні головно, якщо у вас був застосунок FastAPI старіший за 0.121.0 і ви стикаєтеся з проблемами залежностей із `yield`.

///

Залежності з `yield` еволюціонували з часом, щоб охопити різні сценарії використання та виправити деякі проблеми, ось підсумок змін.

### Залежності з `yield` і `scope` { #dependencies-with-yield-and-scope }

У версії 0.121.0 **FastAPI** додано підтримку `Depends(scope="function")` для залежностей з `yield`.

З `Depends(scope="function")` завершальний код після `yield` виконується одразу після завершення *функції операції шляху*, до того як відповідь буде надіслана клієнту.

А при використанні `Depends(scope="request")` (типове значення) завершальний код після `yield` виконується після відправлення відповіді.

Докладніше читайте в документації: [Залежності з `yield` - Ранній вихід і `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope).

### Залежності з `yield` і `StreamingResponse`, технічні деталі { #dependencies-with-yield-and-streamingresponse-technical-details }

До **FastAPI** 0.118.0, якщо ви використовували залежність із `yield`, завершальний код виконувався після повернення з *функції операції шляху*, але безпосередньо перед відправленням відповіді.

Метою було уникнути утримання ресурсів довше, ніж потрібно, очікуючи, поки відповідь пройде мережею.

Це також означало, що якщо ви повертали `StreamingResponse`, завершальний код залежності з `yield` уже було б виконано.

Наприклад, якщо у залежності з `yield` була сесія бази даних, `StreamingResponse` не зміг би використовувати цю сесію під час потокової передачі даних, тому що сесію вже закрито в завершальному коді після `yield`.

Цю поведінку змінено у 0.118.0: завершальний код після `yield` знову виконується після відправлення відповіді.

/// note

Як побачите нижче, це дуже схоже на поведінку до версії 0.106.0, але з кількома покращеннями та виправленнями помилок у крайових випадках.

///

#### Випадки використання з раннім завершальним кодом { #use-cases-with-early-exit-code }

Є кілька сценаріїв із певними умовами, які можуть виграти від старої поведінки - виконувати завершальний код залежностей з `yield` до надсилання відповіді.

Наприклад, уявіть, що у вас є код, який використовує сесію бази даних у залежності з `yield` лише для перевірки користувача, але сесія більше не використовується у *функції операції шляху*, тільки в залежності, і відправлення відповіді триває довго - як у `StreamingResponse`, що повільно надсилає дані, але з якоїсь причини не використовує базу даних.

У такому разі сесія БД утримувалася б до завершення відправлення відповіді, але якщо ви її не використовуєте, утримувати її немає потреби.

Ось як це може виглядати:

{* ../../docs_src/dependencies/tutorial013_an_py310.py *}

Завершальний код - автоматичне закриття `Session` у:

{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}

...виконається після того, як відповідь завершить надсилати повільні дані:

{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}

Але оскільки `generate_stream()` не використовує сесію бази даних, немає реальної потреби тримати сесію відкритою під час надсилання відповіді.

Якщо у вас саме такий випадок із SQLModel (або SQLAlchemy), ви можете явно закрити сесію, коли вона більше не потрібна:

{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}

Так сесія звільнить з'єднання з базою даних, і його зможуть використовувати інші запити.

Якщо у вас інший сценарій, де потрібно раннє завершення залежності з `yield`, створіть, будь ласка, [питання в обговореннях GitHub](https://github.com/fastapi/fastapi/discussions/new?category=questions) із вашим конкретним випадком і поясненням, чому вам корисне раннє закриття для залежностей з `yield`.

Якщо будуть переконливі приклади для раннього закриття в залежностях з `yield`, я розгляну додавання нового способу увімкнути раннє закриття.

### Залежності з `yield` і `except`, технічні деталі { #dependencies-with-yield-and-except-technical-details }

До **FastAPI** 0.110.0, якщо ви використовували залежність із `yield`, перехоплювали виняток через `except` у цій залежності і не піднімали його знову, виняток автоматично піднімався/пересилався до будь-яких обробників винятків або внутрішнього обробника помилок сервера.

Це змінено у версії 0.110.0, щоб усунути неконтрольоване споживання пам'яті від пересланих винятків без обробника (внутрішні помилки сервера) та зробити поведінку узгодженою зі звичайним Python-кодом.

### Фонові задачі та залежності з `yield`, технічні деталі { #background-tasks-and-dependencies-with-yield-technical-details }

До **FastAPI** 0.106.0 піднімати винятки після `yield` було неможливо: завершальний код у залежностях з `yield` виконувався після надсилання відповіді, тож [обробники винятків](../tutorial/handling-errors.md#install-custom-exception-handlers) уже відпрацювали б.

Так було спроєктовано головно для того, щоб дозволити використовувати ті самі об'єкти, «віддані» залежностями через `yield`, усередині фонових задач, оскільки завершальний код виконувався після завершення фонових задач.

У **FastAPI** 0.106.0 це змінено, щоб не утримувати ресурси під час очікування, поки відповідь піде мережею.

/// tip

Крім того, фонова задача зазвичай є незалежним набором логіки, який слід обробляти окремо, з власними ресурсами (наприклад, власним з'єднанням з базою даних).

Тож так у вас, ймовірно, буде чистіший код.

///

Якщо ви раніше покладалися на цю поведінку, тепер слід створювати ресурси для фонових задач усередині самої фонової задачі та використовувати всередині лише дані, що не залежать від ресурсів залежностей із `yield`.

Наприклад, замість використання тієї самої сесії бази даних ви створюватимете нову сесію в самій фоновій задачі та отримуватимете об'єкти з бази даних, використовуючи Цю нову сесію. І далі, замість передавання об'єкта з бази даних як параметра у функцію фонової задачі, ви передасте ідентифікатор цього об'єкта, а потім отримаєте об'єкт знову всередині функції фонової задачі.
