विषय पर बढ़ें

Dependencies के रूप में Classes

🌐 एआई और मनुष्यों द्वारा किया गया अनुवाद

यह अनुवाद मनुष्यों के मार्गदर्शन में एआई द्वारा किया गया है। 🤝

इसमें मूल अर्थ को गलत समझने या अप्राकृतिक लगने आदि जैसी गलतियाँ हो सकती हैं। 🤖

आप हमें एआई LLM को बेहतर मार्गदर्शन करने में मदद करके इस अनुवाद को बेहतर बना सकते हैं।

अंग्रेज़ी संस्करण

Dependency Injection system में और गहराई में जाने से पहले, पिछले उदाहरण को बेहतर बनाते हैं।

पिछले उदाहरण से एक dict

पिछले उदाहरण में, हम अपनी dependency ("dependable") से एक dict return कर रहे थे:

from typing import Annotated

from fastapi import Depends, FastAPI

app = FastAPI()


async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
    return {"q": q, "skip": skip, "limit": limit}


@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
    return commons


@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
    return commons
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI

app = FastAPI()


async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
    return {"q": q, "skip": skip, "limit": limit}


@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
    return commons


@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
    return commons

लेकिन फिर हमें path operation function के parameter commons में एक dict मिलता है।

और हम जानते हैं कि editors dicts के लिए ज़्यादा support (जैसे completion) नहीं दे सकते, क्योंकि वे उनकी keys और value types नहीं जान सकते।

हम इससे बेहतर कर सकते हैं...

Dependency किससे बनती है

अब तक आपने dependencies को functions के रूप में declare होते देखा है।

लेकिन dependencies declare करने का यही एकमात्र तरीका नहीं है (हालाँकि शायद यह अधिक common होगा)।

मुख्य बात यह है कि dependency एक "callable" होनी चाहिए।

Python में "callable" वह कोई भी चीज़ है जिसे Python एक function की तरह "call" कर सकता है।

तो, अगर आपके पास कोई object something है (जो शायद function हो) और आप उसे इस तरह "call" (execute) कर सकते हैं:

something()

या

something(some_argument, some_keyword_argument="foo")

तो वह एक "callable" है।

Dependencies के रूप में Classes

आप ध्यान दे सकते हैं कि Python class का instance बनाने के लिए भी आप वही syntax उपयोग करते हैं।

उदाहरण के लिए:

class Cat:
    def __init__(self, name: str):
        self.name = name


fluffy = Cat(name="Mr Fluffy")

इस case में, fluffy class Cat का एक instance है।

और fluffy बनाने के लिए, आप Cat को "call" कर रहे हैं।

इसलिए, Python class भी एक callable है।

फिर, FastAPI में, आप Python class को dependency के रूप में उपयोग कर सकते हैं।

FastAPI वास्तव में यह check करता है कि वह एक "callable" (function, class या कुछ और) है और उसमें parameters defined हैं।

अगर आप FastAPI में dependency के रूप में कोई "callable" pass करते हैं, तो यह उस "callable" के parameters को analyze करेगा, और उन्हें path operation function के parameters की तरह ही process करेगा। इसमें sub-dependencies भी शामिल हैं।

यह उन callables पर भी लागू होता है जिनमें कोई parameters नहीं होते। ठीक वैसे ही जैसे बिना parameters वाले path operation functions के लिए होता।

फिर, हम ऊपर वाली dependency "dependable" common_parameters को class CommonQueryParams में बदल सकते हैं:

from typing import Annotated

from fastapi import Depends, FastAPI

app = FastAPI()


fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
    response = {}
    if commons.q:
        response.update({"q": commons.q})
    items = fake_items_db[commons.skip : commons.skip + commons.limit]
    response.update({"items": items})
    return response
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI

app = FastAPI()


fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
    response = {}
    if commons.q:
        response.update({"q": commons.q})
    items = fake_items_db[commons.skip : commons.skip + commons.limit]
    response.update({"items": items})
    return response

Class का instance बनाने के लिए उपयोग की गई __init__ method पर ध्यान दें:

from typing import Annotated

from fastapi import Depends, FastAPI

app = FastAPI()


fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
    response = {}
    if commons.q:
        response.update({"q": commons.q})
    items = fake_items_db[commons.skip : commons.skip + commons.limit]
    response.update({"items": items})
    return response
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI

app = FastAPI()


fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
    response = {}
    if commons.q:
        response.update({"q": commons.q})
    items = fake_items_db[commons.skip : commons.skip + commons.limit]
    response.update({"items": items})
    return response

...इसमें वही parameters हैं जो हमारे पिछले common_parameters में थे:

from typing import Annotated

from fastapi import Depends, FastAPI

app = FastAPI()


async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
    return {"q": q, "skip": skip, "limit": limit}


@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
    return commons


@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
    return commons
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI

app = FastAPI()


async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
    return {"q": q, "skip": skip, "limit": limit}


@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
    return commons


@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
    return commons

यही parameters FastAPI dependency को "solve" करने के लिए उपयोग करेगा।

दोनों cases में, इसमें होगा:

  • एक optional q query parameter जो str है।
  • एक skip query parameter जो int है, जिसका default 0 है।
  • एक limit query parameter जो int है, जिसका default 100 है।

दोनों cases में data converted, validated, OpenAPI schema पर documented, आदि किया जाएगा।

इसका उपयोग करें

अब आप इस class का उपयोग करके अपनी dependency declare कर सकते हैं।

from typing import Annotated

from fastapi import Depends, FastAPI

app = FastAPI()


fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
    response = {}
    if commons.q:
        response.update({"q": commons.q})
    items = fake_items_db[commons.skip : commons.skip + commons.limit]
    response.update({"items": items})
    return response
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI

app = FastAPI()


fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
    response = {}
    if commons.q:
        response.update({"q": commons.q})
    items = fake_items_db[commons.skip : commons.skip + commons.limit]
    response.update({"items": items})
    return response

FastAPI CommonQueryParams class को call करता है। यह उस class का एक "instance" बनाता है और वह instance आपके function को parameter commons के रूप में pass किया जाएगा।

Type annotation बनाम Depends

ध्यान दें कि ऊपर के code में हम CommonQueryParams को दो बार कैसे लिखते हैं:

commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]

सुझाव

संभव हो तो Annotated version का उपयोग करना बेहतर है।

commons: CommonQueryParams = Depends(CommonQueryParams)

आखिरी CommonQueryParams, इसमें:

... Depends(CommonQueryParams)

...वही है जिसे FastAPI वास्तव में यह जानने के लिए उपयोग करेगा कि dependency क्या है।

FastAPI इसी से declared parameters extract करेगा और वास्तव में इसी को call करेगा।


इस case में, पहला CommonQueryParams, इसमें:

commons: Annotated[CommonQueryParams, ...

सुझाव

संभव हो तो Annotated version का उपयोग करना बेहतर है।

commons: CommonQueryParams ...

...का FastAPI के लिए कोई विशेष अर्थ नहीं है। FastAPI इसे data conversion, validation, आदि के लिए उपयोग नहीं करेगा। (क्योंकि वह इसके लिए Depends(CommonQueryParams) का उपयोग कर रहा है)।

आप वास्तव में सिर्फ यह लिख सकते हैं:

commons: Annotated[Any, Depends(CommonQueryParams)]

सुझाव

संभव हो तो Annotated version का उपयोग करना बेहतर है।

commons = Depends(CommonQueryParams)

...जैसे:

from typing import Annotated, Any

from fastapi import Depends, FastAPI

app = FastAPI()


fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


@app.get("/items/")
async def read_items(commons: Annotated[Any, Depends(CommonQueryParams)]):
    response = {}
    if commons.q:
        response.update({"q": commons.q})
    items = fake_items_db[commons.skip : commons.skip + commons.limit]
    response.update({"items": items})
    return response
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI

app = FastAPI()


fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


@app.get("/items/")
async def read_items(commons=Depends(CommonQueryParams)):
    response = {}
    if commons.q:
        response.update({"q": commons.q})
    items = fake_items_db[commons.skip : commons.skip + commons.limit]
    response.update({"items": items})
    return response

लेकिन type declare करने को प्रोत्साहित किया जाता है क्योंकि इस तरह आपका editor जान पाएगा कि parameter commons के रूप में क्या pass होगा, और फिर यह code completion, type checks, आदि में आपकी मदद कर सकता है:

Shortcut

लेकिन आप देखते हैं कि यहाँ कुछ code repetition हो रहा है, CommonQueryParams को दो बार लिखते हुए:

commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]

सुझाव

संभव हो तो Annotated version का उपयोग करना बेहतर है।

commons: CommonQueryParams = Depends(CommonQueryParams)

FastAPI ऐसे cases के लिए एक shortcut प्रदान करता है, जहाँ dependency specifically एक class है जिसे FastAPI class का instance बनाने के लिए "call" करेगा।

उन specific cases के लिए, आप यह कर सकते हैं:

यह लिखने के बजाय:

commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]

सुझाव

संभव हो तो Annotated version का उपयोग करना बेहतर है।

commons: CommonQueryParams = Depends(CommonQueryParams)

...आप लिखते हैं:

commons: Annotated[CommonQueryParams, Depends()]

सुझाव

संभव हो तो Annotated version का उपयोग करना बेहतर है।

commons: CommonQueryParams = Depends()

आप dependency को parameter के type के रूप में declare करते हैं, और Depends(CommonQueryParams) के अंदर पूरी class को फिर से लिखने के बजाय, आप बिना किसी parameter के Depends() का उपयोग करते हैं।

फिर वही उदाहरण इस तरह दिखेगा:

from typing import Annotated

from fastapi import Depends, FastAPI

app = FastAPI()


fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends()]):
    response = {}
    if commons.q:
        response.update({"q": commons.q})
    items = fake_items_db[commons.skip : commons.skip + commons.limit]
    response.update({"items": items})
    return response
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import Depends, FastAPI

app = FastAPI()


fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends()):
    response = {}
    if commons.q:
        response.update({"q": commons.q})
    items = fake_items_db[commons.skip : commons.skip + commons.limit]
    response.update({"items": items})
    return response

...और FastAPI जान जाएगा कि क्या करना है।

सुझाव

अगर यह मददगार से ज़्यादा confusing लगता है, तो इसे अनदेखा करें, आपको इसकी ज़रूरत नहीं है।

यह सिर्फ एक shortcut है। क्योंकि FastAPI आपको code repetition कम करने में मदद करने की परवाह करता है।