मुख्य सामग्री पर जाएं
Python

Python डिपेंडेंसी इंजेक्शन: मॉड्यूलर और टेस्टेबल कोड बनाएँ

विभिन्न Python डिपेंडेंसी इंजेक्शन फ़्रेमवर्क्स को समझकर और लागू करके अपने कोड को मॉड्यूलर, टेस्टेबल, और मेंटेन करने योग्य बनाना सीखें।
Adejumo Ridwan Suleiman's photo
Adejumo Ridwan Suleiman
अपडेट किया गया · 14 मि॰ पढ़ें

AI के साथ खोजें

ChatGPTClaudePerplexity

अपना निःशुल्क खाता बनाएँ

अभ्यास और ट्रैक अपनी प्रगति को।

Google के साथ जारी रखें
जारी रखने पर, आप हमारी उपयोग की शर्तें, हमारी गोपनीयता नीति को स्वीकार करते हैं और यह भी कि आपका डेटा संयुक्त राज्य अमेरिका में संग्रहीत किया जाता है।

डिपेंडेंसी इंजेक्शन एक डिज़ाइन पैटर्न है जिसमें किसी क्लास को उसके ऑब्जेक्ट्स या सर्विसेज़ (यहाँ आशय डिपेंडेंसियों से है) बाहर से उपलब्ध कराई जाती हैं, बजाय इसके कि क्लास उन्हें अंदर ही बनाए। इससे कंपोनेंट्स आपस में कम जुड़े रहते हैं।

Python में डिपेंडेंसी इंजेक्शन का उपयोग करने के कई लाभ हैं, जैसे:

  • मॉड्यूलैरिटी: आपका कोड छोटे, पुन: प्रयोज्य भागों में बंट जाता है।
  • टेस्टेबिलिटी: कोड का परीक्षण आसान हो जाता है क्योंकि आप वास्तविक भागों को मॉक से बदल सकते हैं।
  • मेंटेनेबिलिटी: आप अपने कोड के हिस्सों को अपडेट या संशोधित कर सकते हैं बिना सिस्टम के बाकी भागों को तोड़े। 

इस ट्यूटोरियल में, मैं सरल, व्यावहारिक उदाहरणों के माध्यम से Python में डिपेंडेंसी इंजेक्शन का उपयोग दिखाऊँगा।

संक्षेप में

  • डिपेंडेंसी इंजेक्शन एक डिज़ाइन पैटर्न है जिसमें कोई क्लास अपनी डिपेंडेंसियाँ खुद बनाने के बजाय उन्हें बाहर से प्राप्त करती है। यह आपके कोड को अधिक मॉड्यूलर बनाता है।

  • आप डिपेंडेंसियाँ कंस्ट्रक्टर, किसी सेटर मेथड, या सीधे किसी मेथड में इंजेक्ट कर सकते हैं, और Python इसे मैन्युअल रूप से या dependency-injector, injector, और punq जैसे फ़्रेमवर्क्स के ज़रिए सपोर्ट करता है।

  • लोकप्रिय वेब फ़्रेमवर्क इसे अलग तरह से संभालते हैं: FastAPI में Depends() के ज़रिए बिल्ट-इन सपोर्ट है। Flask और Django को dependency-injector जैसी लाइब्रेरी चाहिए।

Python में डिपेंडेंसी इंजेक्शन को समझना

डिपेंडेंसी इंजेक्शन को लागू करने के लिए, इसके प्रमुख सिद्धांतों को समझना ज़रूरी है।

डिपेंडेंसी इंजेक्शन इनवर्ज़न ऑफ कंट्रोल (IoC) सिद्धांत पर आधारित है, जिसका अर्थ है कि कोई क्लास अपनी डिपेंडेंसियाँ बनाने और प्रबंधित करने के बजाय उन्हें किसी बाहरी स्रोत से प्राप्त करती है। इससे प्रत्येक भाग एक कार्य पर केंद्रित रहता है और आपका कोड साफ़ होता है।

Python में डिपेंडेंसियाँ इंजेक्ट करने के कुछ सामान्य तरीके ये हैं, यद्यपि अन्य भी हैं:

  • कंस्ट्रक्टर इंजेक्शन: डिपेंडेंसियाँ क्लास के कंस्ट्रक्टर के माध्यम से पास करें।
  • सेटर इंजेक्शन: ऑब्जेक्ट बनने के बाद किसी सेटर मेथड से डिपेंडेंसियाँ सेट करें।
  • मेथड इंजेक्शन: डिपेंडेंसियाँ सीधे उस मेथड को पास करें जिसे उनकी ज़रूरत है।

Python में डिपेंडेंसी इंजेक्शन क्यों इस्तेमाल करें?

एक डेवलपर के रूप में, डिपेंडेंसी इंजेक्शन को समझना और लागू करना आपके कोड डिज़ाइन में बड़ा फ़र्क ला सकता है। आइए इसके कुछ फ़ायदों पर नज़र डालें।

मॉड्यूलैरिटी, पुन: प्रयोज्यता, और लचीलापन

डिपेंडेंसी इंजेक्शन आपको कोड को छोटे, अधिक केंद्रित कंपोनेंट्स में बाँटने में सक्षम बनाता है, जिससे लचीलापन और मॉड्यूलैरिटी बढ़ती है। 

हर भाग एक विशिष्ट कार्य संभालता है और बाहरी डिपेंडेंसियों पर निर्भर होता है, जिससे उसे आपके या किसी और के एप्लिकेशन के विभिन्न हिस्सों में फिर से उपयोग करना आसान हो जाता है।

उदाहरण के लिए, यदि आपके पास संदेश भेजने वाली कोई क्लास है। अपनी सर्विस में ईमेल या SMS लॉजिक सीधे बनाने के बजाय, आप एक ईमेल या SMS सेंडर क्लास इंजेक्ट कर सकते हैं। 

अब, आपका मैसेज भेजने वाला क्लास इस बात की परवाह नहीं करता कि संदेश कैसे भेजा जाता है, वह बस दिए गए सेंडर का उपयोग करता है। इसका मतलब है कि आप अपने मैसेजिंग सेंडर को विभिन्न ईमेल या SMS सेंडर्स के साथ इस्तेमाल कर सकते हैं। 

मेंटेनेबिलिटी और टेस्टेबिलिटी

डिपेंडेंसी इंजेक्शन का उपयोग करते समय, आप परीक्षण के दौरान वास्तविक डिपेंडेंसियों को मॉक डेटा से आसानी से बदल सकते हैं। इससे यूनिट टेस्ट लिखना सरल हो जाता है क्योंकि आपको APIs या डेटाबेस पर निर्भर नहीं रहना पड़ता। 

मान लें, एक विचार अभ्यास के रूप में, कि आपके पास एक क्लास है जो डेटा को डेटाबेस में सेव करता है। परीक्षण के लिए, आप प्रोडक्शन डेटाबेस से जुड़ाव से बचने हेतु वास्तविक के बजाय एक मॉक डेटाबेस इंजेक्ट कर सकते हैं।

डिपेंडेंसी इंजेक्शन आपको अपने कोड के किसी हिस्से में बदलाव करने देता है बिना पूरे सिस्टम को तोड़े। यह खासकर तब उपयोगी होता है जब आपको किसी एप्लिकेशन में पेमेंट प्रोवाइडर बदलना हो, जैसे Stripe से PayPal, बिना बाकी कोड में बदलाव किए।

इनवर्ज़न ऑफ कंट्रोल और स्वैपेबल डिपेंडेंसियाँ

इनवर्ज़न ऑफ कंट्रोल का विचार यह है: डिपेंडेंसी इंजेक्शन डिपेंडेंसियों को बनाने और प्रबंधित करने की ज़िम्मेदारी किसी बाहरी स्रोत को स्थानांतरित कर देता है। 

इसका तात्पर्य है कि आप एक इम्प्लीमेंटेशन को दूसरे से आसानी से बदल सकते हैं; उदाहरण के लिए, यदि आपके पास एक ReportGenerator क्लास है जो रिपोर्टों को फ़ॉर्मैट और एक्सपोर्ट करता है। 

क्लास को यह तय करने देने के बजाय कि किस फ़ॉर्मैट में एक्सपोर्ट करना है, आप इसमें PDFExporter, ExcelExporter, या CSVExporter जैसा एक्सपोर्टर क्लास इंजेक्ट कर सकते हैं।

ReportGenerator क्लास को इस बात से फ़र्क नहीं पड़ता कि एक्सपोर्ट कैसे होता है, इसलिए फ़ॉर्मैट बदलने के लिए, आप बस इंजेक्ट किया गया एक्सपोर्टर बदल दें, बिना ReportGenerator में कोई संशोधन किए। 

Python में डिपेंडेंसी इंजेक्शन लागू करना

अब जब आपको यह स्पष्ट हो गया है कि डिपेंडेंसी इंजेक्शन क्या है और यह क्यों उपयोगी है, तो देखते हैं कि आप इसे Python में कैसे लागू कर सकते हैं। सबसे सरल तरीके से शुरू करते हैं: मैन्युअल डिपेंडेंसी इंजेक्शन।

मैन्युअल डिपेंडेंसी इंजेक्शन

मैन्युअल डिपेंडेंसी इंजेक्शन में, आप डिपेंडेंसियाँ खुद बनाते हैं और उन्हें उस क्लास या फ़ंक्शन में पास करते हैं जिसे उनकी आवश्यकता होती है। 

यह तरीका छोटे अनुप्रयोगों के लिए अच्छी तरह काम करता है, लेकिन जैसे-जैसे आपका एप्लिकेशन स्केल होता है, त्रुटियों से बचने के लिए आपको डिपेंडेंसी इंजेक्शन फ़्रेमवर्क का इस्तेमाल करना चाहिए।

यहाँ डिपेंडेंसी इंजेक्शन के बिना कोड का एक उदाहरण है

class EmailService:
    def send_email(self, message):
        print(f"Sending email: {message}")


class UserNotifier:
    def __init__(self):
        self.email_service = EmailService()  # Creates its own dependency

    def notify(self, message):
        self.email_service.send_email(message)


notifier = UserNotifier()
notifier.notify("Welcome!")

ऊपर के उदाहरण में, UserNotifier EmailService से कड़ा जुड़ा हुआ है। आप परीक्षण के लिए EmailService को आसानी से स्वैप या मॉक नहीं कर सकते। 

यहाँ इसका एक और संस्करण है, पर मैन्युअल डिपेंडेंसी इंजेक्शन के साथ।

class EmailService:
    def send_email(self, message):
        print(f"Sending email: {message}")


class UserNotifier:
    def __init__(self, email_service):
        self.email_service = email_service  # Dependency is injected

    def notify(self, message):
        self.email_service.send_email(message)


email_service = EmailService()
notifier = UserNotifier(email_service)
notifier.notify("Welcome!")

ऊपर वाला संस्करण लचीला है और आपको विभिन्न मैसेजिंग सर्विसेज़ इंजेक्ट करने देता है; आप परीक्षण में EmailService को मॉक से भी बदल सकते हैं।

dependency-injector फ़्रेमवर्क का उपयोग

जैसे-जैसे आपका एप्लिकेशन बढ़ता है, डिपेंडेंसियों को प्रबंधित करना जटिल और अव्यवस्थित हो जाता है। 

dependency-injector फ़्रेमवर्क एक संरचित तरीका प्रदान करता है।

कंटेनर-प्रोवाइडर आर्किटेक्चर

dependency-injector फ़्रेमवर्क कंटेनर-प्रोवाइडर आर्किटेक्चर पर काम करता है। 

  • Container: यह आपके एप्लिकेशन की डिपेंडेंसियों की केंद्रीय रजिस्ट्री है।
  • Providers: यह निर्धारित करता है कि आपकी डिपेंडेंसियाँ कैसे बनाई जाती हैं।
  • Configuration: यह सेटिंग्स को संशोधित करने और उन्हें ऑब्जेक्ट्स में इंजेक्ट करने की अनुमति देता है। 
  • Overriding: आपको एप्लिकेशन कोड बदले बिना डिपेंडेंसियों को बदलने देता है, खासकर परीक्षण के दौरान। 
from dependency_injector import containers, providers


# Services
class EmailService:
    def send_email(self, message):
        print(f"Sending email: {message}")


class UserNotifier:
    def __init__(self, email_service):
        self.email_service = email_service

    def notify(self, message):
        self.email_service.send_email(message)


# Container
class Container(containers.DeclarativeContainer):
    email_service = providers.Singleton(EmailService)
    user_notifier = providers.Factory(UserNotifier, email_service=email_service)


# Usage
container = Container()
notifier = container.user_notifier()
notifier.notify("Hello!")

ऊपर के उदाहरण में:

  • Container यह परिभाषित करता है कि इंस्टैंसेज़ कैसे बनाए जाते हैं

  • Singleton सुनिश्चित करता है कि EmailService का केवल एक ही इंस्टेंस मौजूद हो

  • Factory एक नया UserNotifier बनाता है जिसमें EmailService अपने आप इंजेक्ट हो जाता है।

वायरिंग मैकेनिज़्म

आप डेकोरेटर्स जैसे @inject का उपयोग करके मैन्युअल डिपेंडेंसी पासिंग की ज़रूरत कम कर सकते हैं। 

यह पिछले उदाहरण का एक और संस्करण है:

from dependency_injector import containers, providers


# Define services
class EmailService:
    def send_email(self, message):
        print(f"Sending email: {message}")


class UserNotifier:

    def __init__(self, email_service: EmailService):
        self.email_service = email_service

    def notify(self, message):
        self.email_service.send_email(message)


# Create container
class Container(containers.DeclarativeContainer):
    email_service = providers.Singleton(EmailService)
    user_notifier = providers.Factory(UserNotifier, email_service=email_service)


from dependency_injector.wiring import inject, Provide


@inject
def main(notifier: UserNotifier = Provide[Container.user_notifier]):
    notifier.notify("Hello!")


if __name__ == "__main__":
    container = Container()
    container.wire(modules=[__name__])  # This wires the current module
    main()

वर्तमान संस्करण में;

  • बिना डिपेंडेंसी को मैन्युअली जोड़ने के, @inject डेकोरेटर फ़ंक्शन या क्लास डिपेंडेंसी अपने आप इंजेक्ट कर देता है।

  • Provide क्लास dependency-injector को बताता है कि कौन-सी डिपेंडेंसी इंजेक्ट करनी है।

यह तरीका कंटेनर से डिपेंडेंसियों की मैन्युअल वायरिंग की ज़रूरत खत्म कर देता है। 

यह बड़े एप्लिकेशनों में उपयोगी है जहाँ सर्विसेज़ कई कंपोनेंट्स पर निर्भर हो सकती हैं (इसलिए उन्हें स्वतः इनिशियलाइज़ करने की ज़रूरत होती है)।

लोकप्रिय Python फ़्रेमवर्क्स में डिपेंडेंसी इंजेक्शन

अधिकांश आधुनिक Python फ़्रेमवर्क्स डिपेंडेंसी इंजेक्शन के साथ काम करना आसान बनाते हैं, जिससे आप अधिक साफ़ और टेस्टेबल कोड लिख पाते हैं। 

इस खंड में, आप सीखेंगे कि Flask, Django और FastAPI में डिपेंडेंसी इंजेक्शन कैसे लागू होता है।

Flask में डिपेंडेंसी इंजेक्शन

Flask में डिपेंडेंसी इंजेक्शन के लिए बिल्ट-इन सपोर्ट नहीं है, लेकिन आप निम्न चरणों के माध्यम से dependency-injector लाइब्रेरी का उपयोग करके इसे लागू कर सकते हैं।

चरण 1: अपनी सर्विसेज़ परिभाषित करें

class GreetingService:
    def get_greeting(self, name):
        return f"Hello, {name}!"

चरण 2: अपना डिपेंडेंसी इंजेक्शन कंटेनर सेट करें

from dependency_injector import containers, providers

class Container(containers.DeclarativeContainer):
    greeting_service = providers.Factory(GreetingService)

चरण 3: Flask एप्लिकेशन बनाएँ और डिपेंडेंसियाँ इंजेक्ट करें।

from flask import Flask, request
from dependency_injector.wiring import inject, Provide

container = Container()

app = Flask(__name__)

@app.route("/greet")
@inject
def greet(greeting_service: GreetingService = Provide[Container.greeting_service]):
    name = request.args.get("name", "World")
    return greeting_service.get_greeting(name)

container.wire(modules=[__name__])

if __name__ == "__main__":
    app.run(debug=True)

ऊपर के कोड से:

  • फ़ंक्शन name = request.args.get(“name”, “World”) क्वेरी स्ट्रिंग से name निकालता है, और यदि न दिया हो तो ”World” डिफ़ॉल्ट करता है। 

  • return greeting_service.get_greeting(name) इंजेक्टेड सर्विस पर मेथड कॉल करता है और ग्रीटिंग संदेश लौटाता है। 

  • container.wire(modules=[__name__]) डिपेंडेंसी इंजेक्टर को बताता है कि वह इस मॉड्यूल में @inject डेकोरेटर्स और Provide[...] मार्कर्स स्कैन करे ताकि उन्हें वास्तविक प्रोवाइडर्स से जोड़ा जा सके। 

चरण 4: एप्लिकेशन का परीक्षण करें

अपने टर्मिनल पर python <name_of_file>.py कमांड से एप्लिकेशन चलाएँ, और URL http://localhost:5000/greet?name=Jacob खोलें। 

आपको निम्न दिखाई देना चाहिए।

चलते हुए Flask एप्लिकेशन के URL को दिखाती छवि

Django में डिपेंडेंसी इंजेक्शन

Flask की तरह, Django भी बिल्ट-इन डिपेंडेंसी इंजेक्शन नहीं देता। लेकिन, आप इसकी क्लास-आधारित व्यूज़, मिडलवेयर, और ऐप स्ट्रक्चर का उपयोग करके डिपेंडेंसी इंजेक्शन को मैन्युअल रूप से या dependency-injector लाइब्रेरी से इंटीग्रेट कर सकते हैं। 

यहाँ Django में डिपेंडेंसी इंजेक्शन लागू करने की चरण-दर-चरण प्रक्रिया है। 

चरण 1: अपनी सर्विस परिभाषित करें

अपने ऐप फ़ोल्डर के अंदर नए फ़ाइल services.py में अपने बिज़नेस लॉजिक वाली एक सरल सर्विस बनाएँ। 

# myapp/services.py
class GreetingService:
    def get_greeting(self, name):
        return f"Hello, {name}!"

चरण 2: डिपेंडेंसी इंजेक्टर कंटेनर सेट करें

अपने एप्लिकेशन डायरेक्टरी के अंदर, containers.py नामक नई फ़ाइल में dependency-injector लाइब्रेरी का उपयोग करके कंटेनर बनाएँ।

# myapp/containers.py
from dependency_injector import containers, providers
from .services import GreetingService

class Container(containers.DeclarativeContainer):
    greeting_service = providers.Factory(GreetingService)

चरण 3: इंजेक्टेड डिपेंडेंसियों के साथ एक व्यू बनाएँ

views.py में अपने व्यू में डिपेंडेंसियाँ प्राप्त करने के लिए @inject डेकोरेटर का उपयोग करें।

# myapp/views.py
from django.http import HttpResponse
from dependency_injector.wiring import inject, Provide
from .containers import Container
from .services import GreetingService

@inject
def greet_view(
    request, greeting_service: GreetingService = Provide[Container.greeting_service]
):
    name = request.GET.get("name", "World")
    message = greeting_service.get_greeting(name)
    return HttpResponse(message)

चरण 4: urls.py अपडेट करें

अपने प्रोजेक्ट फ़ोल्डर के अंतर्गत urls.py फ़ाइल पर जाएँ और Django की URL रूटिंग सिस्टम में अपने डिपेंडेंसी इंजेक्टर को हुक करें।

from django.contrib import admin
from django.urls import path
from myapp.views import greet_view

urlpatterns = [
    path("admin/", admin.site.urls),
    path("greet/", greet_view),
]

चरण 5: apps.py में कंटेनर वायर करें 

apps.py पर जाएँ और कंटेनर को एप्लिकेशन से वायर करें। 

 # myapp/apps.py
from django.apps import AppConfig
from .containers import Container

class MyAppConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "myapp"

    def ready(self):
        container = Container()
        container.wire(modules=["myapp.views"])

फिर अपने ऐप कॉन्फ़िग को INSTALLED_APPS में जोड़ें।

# settings.py
INSTALLED_APPS = [
    'myapp.apps.MyAppConfig',
    ...
]

चरण 6: व्यू का परीक्षण करें

अपना Django सर्वर शुरू करें और URL http://localhost:8000/greet/?name=Django के माध्यम से व्यू तक पहुँचें। 

आपको निम्न दिखाई देना चाहिए।

चलते हुए Django एप्लिकेशन को दिखाती छवि।

FastAPI में डिपेंडेंसी इंजेक्शन

FastAPI में डिपेंडेंसी इंजेक्शन के लिए Depends() नामक विशेष मार्कर के माध्यम से बिल्ट-इन सपोर्ट है जो किसी फ़ंक्शन के रिटर्न को इंजेक्ट करता है। 

यहाँ FastAPI डिपेंडेंसी इंजेक्शन के बारे में चरण-दर-चरण मार्गदर्शिका है।

चरण 1: एक सर्विस परिभाषित करें

class GreetingService:
    def get_greeting(self, name: str) -> str:
        return f"Hello, {name}!"

चरण 2: डिपेंडेंसी फ़ंक्शन बनाएँ

def get_greeting_service():
    return GreetingService()

चरण 3: FastAPI ऐप सेट करें और डिपेंडेंसी इंजेक्शन का उपयोग करें

app = FastAPI()

@app.get("/greet")
def greet(
    name: str = "World", service: GreetingService = Depends(get_greeting_service)
):
    return {"message": service.get_greeting(name)}

चरण 4: एप्लिकेशन चलाएँ और परीक्षण करें

कमांड uvicorn main:app –reload से अपना सर्वर शुरू करें और URL http://localhost:8000/greet?name=FastAPI पर जाएँ। आपको निम्न प्रतिक्रिया दिखनी चाहिए।

चलते हुए FastAPI एप्लिकेशन को दिखाती छवि।

Python डिपेंडेंसी इंजेक्टर फ़्रेमवर्क्स की तुलना

कई Python डिपेंडेंसी फ़्रेमवर्क्स उपलब्ध हैं, जिनमें अपनी-अपनी खूबियाँ, सिन्टैक्स और उपयोग के मामले हैं। सही फ़्रेमवर्क का चुनाव आपके प्रोजेक्ट के आकार और संरचना पर निर्भर करता है। 

यहाँ कुछ सामान्य Python डिपेंडेंसी इंजेक्शन फ़्रेमवर्क्स की तुलना दी गई है।

फ़्रेमवर्क

सबसे उपयुक्त

खूबियाँ

सीमाएँ

dependency-injector

प्रोडक्शन में उपयोग होने वाले जटिल एप्लिकेशन

फुल-फ़ीचर्ड, तेज़, और कॉन्फ़िगरेबल

विस्तृत/वर्बोज़

injector

सरल और न्यूनतम एप्लिकेशनों के लिए उपयुक्त

साफ़-सुथरा सिन्टैक्स

दूसरों की तुलना में कम उन्नत

pinject

एडवांस्ड बाइंडिंग लॉजिक

ऑटो-वायरिंग

इंट्रोस्पेक्शन के कारण धीमा

punq

सरल एप्लिकेशन

न्यूनतम और तेज़

दूसरों की तुलना में सीमित फीचर्स

FastAPI Depends()

FastAPI एप्लिकेशन

असिंक के लिए बिल्ट-इन सपोर्ट, और टेस्टेबल भी

FastAPI के बाहर पुन: उपयोग योग्य नहीं

Flask-injector

Flask एप्लिकेशन

Flask एप्लिकेशनों के साथ आसान इंटीग्रेशन

injector पर निर्भर

django-injector

Django प्रोजेक्ट्स

व्यूज़ और मिडलवेयर के लिए डिपेंडेंसी इंजेक्शन प्रदान करता है

injector पर निर्भर

उन्नत कार्यान्वयन पैटर्न

जैसे-जैसे आपका एप्लिकेशन कोडबेस बड़ा होता है, डिपेंडेंसी इंजेक्शन को मेंटेन करना चुनौतीपूर्ण हो जाता है। 

आप उन्नत डिपेंडेंसी इंजेक्शन का उपयोग रिक्वेस्ट-स्कोप्ड रिसोर्सेज़, क्लीनअप, और सेपरेशन ऑफ कंसर्न्स जैसे कार्यों को संभालने के लिए कर सकते हैं। 

स्कोप्ड डिपेंडेंसियाँ

स्कोप्ड डिपेंडेंसियाँ आपको यह नियंत्रित करने देती हैं कि कोई डिपेंडेंसी कितने समय तक बनी रहे—जैसे हर रिक्वेस्ट पर नया ऑब्जेक्ट, पूरे ऐप की लाइफ़टाइम में साझा ऑब्जेक्ट, या डेटाबेस कनेक्शनों जैसे रिसोर्सेज़ का स्वतः क्लीनअप। 

अधिकांश डिपेंडेंसी इंजेक्टर फ़्रेमवर्क्स निम्न स्कोप सपोर्ट करते हैं:

  • सिंगलटन: पूरे ऐप के लिए एक ही इंस्टेंस।
  • फ़ैक्टरी: हर इंजेक्शन पर नया इंस्टेंस।
  • थ्रेड-लोकल या रिक्वेस्ट: प्रति थ्रेड/रिक्वेस्ट एक इंस्टेंस।
  • रिसोर्स: सेटअप और टियरडाउन लॉजिक सहित प्रबंधित।

नीचे dependency-injector के साथ नेस्टेड कंटेनर्स द्वारा स्कोप्ड डिपेंडेंसियों का उदाहरण है।

from dependency_injector import containers, providers, resources

# A simple resource that needs setup and cleanup
class MyResource:
    def __enter__(self):
        print("Setting up the resource")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Cleaning up the resource")

# Create a container to manage the resource
class MyContainer(containers.DeclarativeContainer):
    resource = providers.Resource(MyResource)

# Using the resource with a context manager
container = MyContainer()

with container.resource() as r:
    print("Using the resource")

ऊपर के उदाहरण में, MyResource ऐसी क्लास की नकल करता है जिसे सेटअप और टियरडाउन चाहिए, जैसे फ़ाइल या डेटाबेस को खोलना/बंद करना।

container providers.Resource के माध्यम से रिसोर्स प्रदान करता है, और जब आप with container.resource() उपयोग करते हैं, तो यह सही ढंग से कॉन्टेक्स्ट में प्रवेश और बाहर निकलता है।

यह पैटर्न सुनिश्चित करता है कि फ़ाइल हैंडल्स, डेटाबेस कनेक्शंस, या नेटवर्क सेशंस जैसे रिसोर्सेज़ साफ़-सुथरे ढंग से प्रबंधित हों।

ऐसा मान लें कि कोई API एंडपॉइंट वर्तमान रिक्वेस्ट के लिए डेटाबेस सेशन या रिक्वेस्ट-विशिष्ट कॉन्टेक्स्ट वाला लॉगर चाहता है। 

स्कोप्ड डिपेंडेंसियों के साथ, फ़्रेमवर्क रिक्वेस्ट शुरू होते ही एक रिक्वेस्ट-स्कोप्ड कंटेनर बनाता है और सभी डिपेंडेंसियों को उसी स्कोप से रिज़ॉल्व करता है। 

जब रिक्वेस्ट समाप्त होती है, तो आवश्यक क्लीनअप, जैसे डेटाबेस सेशंस को बंद करना, स्वतः हो जाता है। इससे रिक्वेस्ट्स के बीच स्टेट साझा नहीं होता और रिसोर्स लीक से बचाव होता है।

असिंक्रोनस इंजेक्शन

I/O बाउंड टास्क्स को कुशलता से संभालने के लिए, आपको असिंक्रोनस निष्पादन चाहिए। FastAPI और dependency-injector जैसे फ़्रेमवर्क्स के डिपेंडेंसी इंजेक्शन सिस्टम async/await के साथ असिंक्रोनस इंजेक्शन प्रदान करते हैं।

असिंक्रोनस इंजेक्शन का मतलब है ऐसी डिपेंडेंसियों को इंजेक्ट करना जो async def फ़ंक्शंस हों या async resources जैसे असिंक डेटाबेस कनेक्शन, बाहरी APIs, या बैकग्राउंड टास्क्स को मैनेज करना। 

उन्हें सिंक्रोनसली रिज़ॉल्व करने के बजाय, डिपेंडेंसी इंजेक्शन सिस्टम उनके रिज़ॉल्व होने का इंतज़ार करता है और फिर इंजेक्ट करता है। 

नीचे FastAPI में एक असिंक डिपेंडेंसी का उदाहरण है:

from fastapi import FastAPI, Depends

app = FastAPI()

# Async dependency
async def get_user():
    # Simulate async I/O
    await some_async_db_query()
    return {"name": "Philip Jones"}

@app.get("/profile")
async def read_profile(user: dict = Depends(get_user)):
    return {"user": user}

FastAPI स्वतः get_user के असिंक रिज़ॉल्यूशन को संभालता है और परिणाम इंजेक्ट करता है।

dependency-injector भी AsyncResource प्रोवाइडर्स के माध्यम से असिंक लाइफ़साइकल मैनेजमेंट सपोर्ट करता है।

from dependency_injector import containers, providers, resources

class AsyncDB:
    async def connect(self):
        print("Connected")
        return self

    async def disconnect(self):
        print("Disconnected")

class AsyncDBResource(resources.AsyncResource):
    async def init(self) -> AsyncDB:
        db = AsyncDB()
        return await db.connect()

    async def shutdown(self, db: AsyncDB):
        await db.disconnect()

class Container(containers.DeclarativeContainer):
    db = providers.Resource(AsyncDBResource)

# Usage
async def main():
    container = Container()
    await container.init_resources()

    db = await container.db()  # Get the AsyncDB instance

    # Use db here...

    await container.shutdown_resources()

ऊपर के कोड में:

  • resources.AsyncResource असिंक सेटअप/टियरडाउन लॉजिक के लिए उपयोग होता है।

  • await container.init_resources() सभी रिसोर्सेज़ इनिशियलाइज़ करता है और init कॉल करता है।

  • await container.shutdown_resources() सभी रिसोर्सेज़ को क्लीनअप करता है।

  • await container.db() वास्तविक रिसोर्स इंस्टेंस प्राप्त करता है, जो AsyncDB है।

असिंक डिपेंडेंसी इंजेक्शन का उपयोग आपके एप्लिकेशन को परफ़ॉर्मेंट रखता है क्योंकि यह असिंक्रोनस रूट्स में सिंक्रोनस I/O से बचाता है, और आपके लॉजिक में डिपेंडेंसियों को मैन्युअली await करने की आवश्यकता समाप्त करता है। 

सुरक्षा संबंधी निहितार्थ

डिपेंडेंसी इंजेक्शन मॉड्यूलैरिटी और टेस्टेबिलिटी में सुधार करता है, लेकिन यदि सावधानी से प्रबंधित न किया जाए तो संभावित सुरक्षा जोखिम भी पैदा कर सकता है।

एक बड़ा जोखिम डिपेंडेंसी कन्फ्यूज़न है, जहाँ दुर्भावनापूर्ण पैकेज वैध पैकेजों की नकल करते हैं। उदाहरण के लिए, हमलावरों ने PyPI पर ऐसे नामों के साथ पैकेज अपलोड किए हैं जो आंतरिक एंटरप्राइज़ सिस्टम में उपयोग होते हैं, ताकि ऐप्स को दुर्भावनापूर्ण संस्करण उपयोग करने के लिए धोखा दिया जा सके।

सुरक्षित रहने के लिए, सुनिश्चित करें कि आप कभी भी अविश्वसनीय या यूज़र-नियंत्रित कंपोनेंट्स इंजेक्ट न करें और इंजेक्ट करने से पहले पर्यावरण चर जैसे कॉन्फ़िगरेशन स्रोतों को वैलिडेट करें।

सटीक वर्ज़न लॉक करने के लिए requirements.txt या poetry.lock फ़ाइलों का उपयोग करें, और डिपेंडेंसी परिवर्तनों पर सुरक्षा स्कैनिंग को स्वचालित करें। साथ ही, अपने डिपेंडेंसियों का नियमित रूप से ऑडिट करें।

अपनी डिपेंडेंसियों का केंद्रीकृत नियंत्रण भी आवश्यक है, क्योंकि यह आपके एप्लिकेशनों में स्थिरता सुनिश्चित करता है और सुरक्षा पैचेस या वर्ज़न अपडेट्स को लागू करना आसान बनाता है। यह कोडबेस में अलग-अलग तरीक़ों से इंजेक्ट होने वाली "शैडो डिपेंडेंसियों" से बचने में मदद करता है। 

कई टूल जोखिमों का पता लगा सकते हैं और आपकी सुरक्षा स्थिति में सुधार कर सकते हैं:

  • Snyk: Python पैकेजों में ज्ञात कमजोरियों को स्कैन करता है और समाधान सुझाता है।
  • Xygeni: CI/CD पाइपलाइंस के लिए सुरक्षा प्रदान करता है।
  • Safety: असुरक्षित पैकेजों और कोड कमजोरियों की जाँच करता है।
  • Bandit: सुरक्षा मुद्दों पर केंद्रित Python के लिए एक स्टैटिक कोड एनालाइज़र।

वास्तविक दुनिया के उपयोग

डिपेंडेंसी इंजेक्शन केवल सैद्धांतिक पैटर्न नहीं है; इसे विभिन्न प्रोडक्शन सिस्टम्स में जटिलता प्रबंधन, लचीलापन बढ़ाने, और टेस्टिंग को सुव्यवस्थित करने के लिए उपयोग किया जाता है। 

वेब सर्विस कॉन्फ़िगरेशन

आधुनिक वेब एप्लिकेशनों में, डिपेंडेंसी इंजेक्शन ऑथेंटिकेशन, लॉगिंग, और डेटाबेस एक्सेस जैसी मानक सर्विसेज़ को प्रबंधित करने में महत्वपूर्ण भूमिका निभाता है। 

FastAPI जैसे फ़्रेमवर्क रूट्स और डिपेंडेंसियों को रिज़ॉल्व करने में अहम भूमिका निभाते हैं।

नीचे का उदाहरण FastAPI में केंद्रीकृत ऑथेंटिकेशन का कार्यान्वयन दर्शाता है।

from fastapi import Depends, HTTPException

def get_current_user(token: str = Depends(oauth2_scheme)):
    user = verify_token(token)
    if not user:
        raise HTTPException(status_code=401)
    return user

@app.get("/protected")
def protected_route(user: dict = Depends(get_current_user)):
    return {"message": f"Hello {user['name']}"}

ऊपर के कोड में, get_current_user() को रूट डिपेंडेंसी के रूप में इंजेक्ट किया गया है, लेकिन टोकन जाँचने का लॉजिक केंद्रीकृत और पुन: प्रयोज्य है।

आप डेटाबेस एक्सेस के लिए भी यही कर सकते हैं, ताकि डेटाबेस सेशंस स्वतः प्रबंधित और साफ़ किए जाएँ। 

यहाँ डिपेंडेंसी इंजेक्शन का उपयोग करके डेटाबेस एक्सेस को केंद्रीकृत करने का उदाहरण है।

from sqlalchemy.ext.asyncio import AsyncSession

async def get_db_session() -> AsyncSession:
    async with async_session() as session:
        yield session

@app.get("/items")
async def read_items(db: AsyncSession = Depends(get_db_session)):
    return await db.execute("SELECT * FROM items")

ऊपर के कोड में, get_db_session एक डिपेंडेंसी प्रोवाइडर है। जब read_items रूट कॉल होता है, FastAPI db पैरामीटर अपने आप इंजेक्ट करता है, जिससे रूट सेशन सेटअप या टियरडाउन को मैन्युअली मैनेज किए बिना डेटाबेस तक पहुँच सकता है। 

टेस्ट-ड्रिवन डेवलपमेंट

डिपेंडेंसी इंजेक्शन से आप आसानी से कंपोनेंट्स को मिलने वाली डिपेंडेंसियों को बदल सकते हैं, जो परीक्षण के समय महत्वपूर्ण है। 

परीक्षण के दौरान आप वास्तविक सर्विसेज़ को मॉक्स से बदल सकते हैं, जिससे आपका कोड अधिक मॉड्यूलर और टेस्ट करना आसान हो जाता है। 

FastAPI और dependency-injector परीक्षण के समय डिपेंडेंसियों को ओवरराइड करना सपोर्ट करते हैं। 

यहाँ FastAPI में एक उदाहरण है।

from fastapi.testclient import TestClient
from main import app, get_db_session

def override_db():
    return TestDBSession()

app.dependency_overrides[get_db_session] = override_db

client = TestClient(app)
response = client.get("/items")
assert response.status_code == 200

ऊपर के उदाहरण में, परीक्षण के दौरान get_db_session को मॉक डेटाबेस से ओवरराइड किया गया है; इसलिए प्रोडक्शन कोड को पैच या बदलने की ज़रूरत नहीं है।

इसी तरह depedency-injector में भी, आप परीक्षण उद्देश्यों के लिए अपने वास्तविक डेटाबेस को मॉक डेटाबेस से ओवरराइड कर सकते हैं, जैसे नीचे के उदाहरण में।

from containers import Container

def test_service_behavior():
    container = Container()
    container.db.override(providers.Factory(TestDB))

    service = container.service()
    assert service.get_data() == "mocked"

override() मेथड वास्तविक डिपेंडेंसी को मॉक से बदल देता है, जो साफ़, नियंत्रित, और रिवर्स करने योग्य होता है। 

डिपेंडेंसी ओवरराइड्स के लिए आपको निम्न रणनीतियाँ अपनानी चाहिए:

  • कंस्ट्रक्टर इंजेक्शन: मॉक को सीधे कंस्ट्रक्टर में पास करें।
  • फ़्रेमवर्क ओवरराइड्स: बिल्ट-इन ओवरराइड टूल्स का उपयोग करें जैसे FastAPI में FastAPI.dependency_overrides या dependency-injector में dependency_injector.override()।
  • फिक्स्चर्स: pytest जैसे टेस्टिंग फ़्रेमवर्क्स का उपयोग करके पुन: प्रयोज्य मॉक्स बनाएँ और उन्हें फिक्स्चर्स के माध्यम से इंजेक्ट करें।

सर्वोत्तम अभ्यास और एंटी-पैटर्न्स

यद्यपि डिपेंडेंसी इंजेक्शन कोड को मॉड्यूलर और टेस्ट करना आसान बनाने के लिए होता है, यह बग्स ला सकता है या कोड में जटिलता बढ़ा सकता है। 

अनुशंसित अभ्यास

डिपेंडेंसियाँ बनाते समय आपको इन सर्वोत्तम अभ्यासों का पालन करना चाहिए:

  • इम्प्लीमेंटेशनों नहीं, इंटरफेसेज़ पर प्रोग्राम करें: जटिल इम्प्लीमेंटेशनों के बजाय एब्स्ट्रैक्ट बेस क्लासेस या इंटरफेसेज़ के ज़रिए डिपेंडेंसियाँ परिभाषित करें। इससे कोड का परीक्षण आसान होता है और यूनिट टेस्ट्स में मॉक्स के उपयोग को प्रोत्साहन मिलता है।
  • इनहेरिटेंस पर कंपोज़िशन को प्राथमिकता दें: जटिल क्लास हायरार्कियाँ बनाने के बजाय, इंजेक्ट की गई डिपेंडेंसियों के साथ ऑब्जेक्ट्स को कंपोज़ करके कंपोनेंट्स को छोटा और केंद्रित रखें।
  • केंद्रीकृत डिपेंडेंसी कॉन्फ़िगरेशन: डिपेंडेंसियों को परिभाषित और प्रबंधित करने के लिए एक ही कंटेनर या मॉड्यूल का उपयोग करें, जिससे ओवरराइडिंग और टेस्टिंग आसान हो।
  • सर्कुलर डिपेंडेंसियों से बचें: अपने डिपेंडेंसी ग्राफ़ को सावधानी से डिज़ाइन करें ताकि सर्कुलर रेफ़रेंसेज़ से बचा जा सके—इंस्टैंशिएशन में देरी के लिए फ़ैक्टरी फ़ंक्शंस या प्रोवाइडर्स का उपयोग करें।

आम गलतियाँ

डिपेंडेंसी इंजेक्शन का उपयोग करते समय आपको इन आम गलतियों से बचना चाहिए।

  • सर्विस लोकेटर एंटी-पैटर्न: डिपेंडेंसियों को डायनामिकली फ़ेच करने के लिए किसी ग्लोबल कंटेनर का उपयोग करने से बचें, क्योंकि यह डिपेंडेंसियों को छुपा सकता है और कोड को समझना व टेस्ट करना मुश्किल बना सकता है।
  • ओवर-इंजेक्शन: एक ही क्लास या फ़ंक्शन में बहुत अधिक सर्विसेज़ इंजेक्ट करने से बचें ताकि कंस्ट्रक्टर्स फूले नहीं और लॉजिक का परीक्षण कठिन न हो।
  • स्कोप का गलत प्रबंधन और स्टेट लीकेज: हमेशा सही स्कोप का उपयोग करें ताकि यूज़र्स या टेस्ट्स के बीच स्टेट साझा न हो।

Python में डिपेंडेंसी इंजेक्शन टेस्टिंग

डिपेंडेंसी इंजेक्शन से आप अपने कंपोनेंट्स में मॉक ऑब्जेक्ट्स इंजेक्ट करना आसान बनाते हैं, जिससे यूनिट टेस्ट सरल हो जाते हैं। इससे आप मौलिक कंपोनेंट्स को टेस्ट-विशिष्ट कंपोनेंट्स से अलग कर सकते हैं।

डिपेंडेंसी इंजेक्शन के साथ, टेस्ट निर्धार्य (डेटरमिनिस्टिक) होते हैं, साइड इफेक्ट्स नहीं होते, और तेज़ी से चलते हैं। 

यहाँ एक उदाहरण है जो दिखाता है कि आप अपने टेस्ट्स में डिपेंडेंसियों के मॉक, स्टब, या फेक संस्करण कैसे इंजेक्ट कर सकते हैं। 

class EmailService:
    def send_email(self, to: str, message: str): ...

class Notifier:
    def __init__(self, email_service: EmailService):
        self.email_service = email_service

    def alert(self, user_email):
        self.email_service.send_email(user_email, "Alert!")

टेस्ट्स में, EmailService को मॉक से बदलें:

class TestEmailService:
    def send_email(self, to, message):
        self.sent_to = to

def test_notifier_sends_email():
    test_email = TestEmailService()
    notifier = Notifier(test_email)

    notifier.alert("test@example.com")
    assert test_email.sent_to == "test@example.com"

मेंटेनबिलिटी के लिए डिपेंडेंसी इंजेक्शन का अधिक उपयोग करें और मंकी पैचिंग से बचें ताकि आंतरिक नाम बदलने पर ब्रेकिंग बदलाव न आएँ।

निष्कर्ष

हालाँकि छोटे प्रोजेक्ट्स में आपको शुरू में डिपेंडेंसी इंजेक्शन की आवश्यकता न हो, जैसे-जैसे प्रोजेक्ट बढ़ता और स्केल होता है, आप डिपेंडेंसी इंजेक्शन की संरचना और मॉड्यूलैरिटी से लाभान्वित होंगे। 

आगे देखते हुए, Python में डिपेंडेंसी इंजेक्शन का भविष्य आशाजनक है, और हम बेहतर टाइप सिस्टम और उन्नत असिंक लाइफ़साइकल मैनेजमेंट की उम्मीद कर सकते हैं।

डिपेंडेंसी इंजेक्शन में निपुण होना एक दक्ष Python डेवलपर बनने के लिए आवश्यक है। लेकिन बात यहीं नहीं रुकती; कई अन्य उन्नत अवधारणाएँ हैं जो आपकी Python स्किल्स को ऊँचा उठा सकती हैं। 

आपकी सीखने की यात्रा को तेज़ करने के लिए, यहाँ हमारे कुछ संसाधन हैं जिन्हें आपको देखना चाहिए।

कोर्सेज़:

ब्लॉग पोस्ट्स:


Adejumo Ridwan Suleiman's photo
Author
Adejumo Ridwan Suleiman
LinkedIn

अनुभवी डेटा साइंस प्रशिक्षक और बायोस्टैटिस्टिशियन, Python, R और मशीन लर्निंग में विशेषज्ञता के साथ।

FAQs

डिपेंडेंसी इंजेक्शन क्या है?

डिपेंडेंसी इंजेक्शन एक डिज़ाइन पैटर्न है जो आपको क्लास के भीतर बनने वाली डिपेंडेंसियों को बाहर से पास करके क्लीनर कोड लिखने में सक्षम बनाता है, जिससे आपका कोड प्रबंधित और संशोधित करना आसान हो जाता है।

डिपेंडेंसी इंजेक्शन के मुख्य लाभ क्या हैं?

डिपेंडेंसी इंजेक्शन आपके कोड को मॉड्यूलर, टेस्टेबल, और मेंटेन करने योग्य बनाता है।

मैं Python में डिपेंडेंसी इंजेक्शन कैसे लागू कर सकता/सकती हूँ?

आप Python में डिपेंडेंसी इंजेक्शन को मैन्युअल रूप से या dependency_injector जैसी लाइब्रेरीज़ का उपयोग करके लागू कर सकते हैं।

असिंक्रोनस इंजेक्शन क्या है?

असिंक्रोनस इंजेक्शन का अर्थ है ऐसी डिपेंडेंसियों को इंजेक्ट करना जो async def फ़ंक्शंस हों या async resources जैसे असिंक डेटाबेस कनेक्शंस, बाहरी APIs, या बैकग्राउंड टास्क्स को मैनेज करना।

डिपेंडेंसी इंजेक्शन के सुरक्षा जोखिम क्या हैं, और मैं उनसे कैसे निपटूँ?

एक बड़ा जोखिम डिपेंडेंसी कन्फ्यूज़न है, जहाँ दुर्भावनापूर्ण पैकेज वैध पैकेजों की नकल करते हैं। इससे बचाव के लिए, आप Snyk, Xygeni, Safety, या Bandit जैसे टूल्स का उपयोग करके अपने कोड और पैकेजों को कमजोरियों के लिए स्कैन कर सकते हैं।

विषय
Python

DataCamp के साथ Python सीखें

कोर्स

डेवलपर्स के लिए Python परिचय

3 घंटा
183.9K
Python में प्रोग्रामिंग की मूल बातें सीखें। कोई पूर्व ज्ञान आवश्यक नहीं!
विवरण देखेंपाठ्यक्रम शुरू करें

कोर्स

Python परिचय

4 घंटा
7.1M
Python के साथ डेटा विश्लेषण की बुनियादी बातें सिर्फ चार घंटे में सीखें। यह ऑनलाइन पाठ्यक्रम Python इंटरफ़ेस का परिचय देगा और लोकप्रिय पैकेजों का अन्वेषण करेगा।

अपना निःशुल्क खाता बनाएँ

अभ्यास और ट्रैक अपनी प्रगति को।

Google के साथ जारी रखें
जारी रखने पर, आप हमारी उपयोग की शर्तें, हमारी गोपनीयता नीति को स्वीकार करते हैं और यह भी कि आपका डेटा संयुक्त राज्य अमेरिका में संग्रहीत किया जाता है।
और देखें