Free tutorials & notes in Hindi & English · Clean code examples 🧰 मुफ़्त PDF और फ़ोटो टूल्स →
🟡 Advanced Python  ·  Lesson 21

Python Decorators

Decorator क्या है?

Decorator एक ऐसा function है जो किसी दूसरे function को लेकर उसमें extra काम जोड़कर नया function लौटाता है – मूल code बदले बिना। आप इसे एक बार लिखते हैं और @ से शुरू होने वाली एक line से जोड़ देते हैं।

असली projects में decorators हर जगह हैं: Flask URL को function से जोड़ने के लिए @app.route इस्तेमाल करता है, Django pages बचाने के लिए @login_required, और Python ख़ुद @property, @staticmethod और @functools.lru_cache देता है।

Decorator के बिनाDecorator के साथ
वही logging/timing code 20 functions में copy करनाLogic एक बार लिखें, हर function के ऊपर @log_call लगाएँ
नियम बदला → 20 जगह बदलावनियम बदला → एक decorator बदलें
Business logic और checks मिले हुएFunction साफ़ रहता है; checks बाहर रहते हैं

Step 1: functions भी objects हैं

Decorators इसलिए काम करते हैं क्योंकि Python में function एक साधारण object है। इसे variable में रख सकते हैं, दूसरे function को दे सकते हैं और function से लौटा सकते हैं।

Python – functions_as_objects.py
def greet(name):
    return f"Namaste, {name}!"

say = greet                 # no brackets: we store the function itself
print(say("Riya"))
print(type(greet))

def run_twice(func, value):  # a function that receives a function
    return func(value) + " " + func(value)

print(run_twice(greet, "Aman"))
Namaste, Riya! <class 'function'> Namaste, Aman! Namaste, Aman!
💡 greet बनाम greet()

greet function object है; greet() उसे चलाकर result देता है। Decorator को greet मिलता है, greet() नहीं।

Step 2: function के अंदर function (closure)

Inner function, outer function के ख़त्म होने के बाद भी उसके variables इस्तेमाल कर सकता है। इसी “याद रखने” को closure कहते हैं, और हर decorator इसी पर बना है।

Python – closure.py
def make_gst_calculator(rate):
    def add_gst(amount):
        return round(amount * (1 + rate / 100), 2)
    return add_gst               # return the inner function

gst_5 = make_gst_calculator(5)    # sweets
gst_18 = make_gst_calculator(18)  # electronics

print(gst_5(200))
print(gst_18(200))
210.0 236.0

Step 3: आपका पहला decorator

अब दोनों विचार जोड़ें। log_call एक function लेता है, एक wrapper बनाता है जो message छापकर मूल function चलाता है, और wrapper लौटा देता है।

Python – first_decorator.py
def log_call(func):
    def wrapper(*args, **kwargs):
        print(f"→ calling {func.__name__} with {args} {kwargs}")
        result = func(*args, **kwargs)
        print(f"← {func.__name__} returned {result}")
        return result
    return wrapper

@log_call
def total_bill(price, qty, discount=0):
    return price * qty - discount

total_bill(120, 3, discount=20)
→ calling total_bill with (120, 3) {'discount': 20} ← total_bill returned 340

@log_call सिर्फ़ एक shortcut है। Python function बनाते ही असल में total_bill = log_call(total_bill) चलाता है।

  • *args, **kwargs से wrapper कोई भी arguments ले सकता है, इसलिए एक decorator हर function पर चलता है।
  • Wrapper से हमेशा return result करें – भूलने पर हर decorated function None लौटाएगा।

Step 4: functools.wraps से नाम और docstring बचाएँ

साधारण wrapper मूल function का नाम और help text छिपा देता है। इससे debugging, documentation और Flask जैसे frameworks टूटते हैं जो function का नाम इस्तेमाल करते हैं। functools.wraps इन्हें copy कर देता है।

Python – wraps_demo.py
import functools

def plain(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

def proper(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@plain
def fees_a():
    """Return the monthly fee."""

@proper
def fees_b():
    """Return the monthly fee."""

print(fees_a.__name__, "|", fees_a.__doc__)
print(fees_b.__name__, "|", fees_b.__doc__)
wrapper | None fees_b | Return the monthly fee.
⚠️ नियम

हर wrapper पर @functools.wraps(func) लगाएँ। एक line लगती है और बाद के उलझाने वाले bugs रुकते हैं।

असली उदाहरण 1: function कितना समय लेता है

Python – timer.py
import functools, time

def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        ms = (time.perf_counter() - start) * 1000
        print(f"{func.__name__} took {'under 50' if ms < 50 else 'over 50'} ms")
        return result
    return wrapper

@timer
def sum_of_squares(n):
    return sum(i * i for i in range(n))

print(sum_of_squares(1000))
sum_of_squares took under 50 ms 332833500

Output हर computer पर एक जैसा रहे, इसलिए exact number की जगह “under/over 50 ms” छापा है; अपने code में f"{ms:.2f} ms" छापें।

असली उदाहरण 2: arguments लेने वाला decorator

Retry की संख्या जैसी settings देने के लिए एक और बाहरी level जोड़ें: एक function जो settings लेकर decorator लौटाए।

Python – retry.py
import functools

def retry(times):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(1, times + 1):
                try:
                    return func(*args, **kwargs)
                except ConnectionError as err:
                    print(f"attempt {attempt} failed: {err}")
            raise ConnectionError(f"{func.__name__} failed {times} times")
        return wrapper
    return decorator

calls = {"n": 0}

@retry(times=3)
def send_sms(phone):
    calls["n"] += 1
    if calls["n"] < 3:                       # fail twice, then succeed
        raise ConnectionError("network busy")
    return f"SMS sent to {phone}"

print(send_sms("98290xxxxx"))
attempt 1 failed: network busy attempt 2 failed: network busy SMS sent to 98290xxxxx
Levelक्या लेता हैक्या लौटाता है
retry(times)settingsdecorator
decorator(func)functionwrapper
wrapper(*args)call के argumentsresult

असली उदाहरण 3: सिर्फ़ logged-in admin को अनुमति

Python – require_role.py
import functools

def require_role(role):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(user, *args, **kwargs):
            if user.get("role") != role:
                return f"403 Forbidden: {user['name']} is not {role}"
            return func(user, *args, **kwargs)
        return wrapper
    return decorator

@require_role("admin")
def delete_student(user, roll_no):
    return f"Student {roll_no} deleted by {user['name']}"

teacher = {"name": "Meena", "role": "teacher"}
admin = {"name": "Gagan", "role": "admin"}
print(delete_student(teacher, 21))
print(delete_student(admin, 21))
403 Forbidden: Meena is not admin Student 21 deleted by Gagan

Django का @login_required और Flask का @jwt_required ठीक ऐसे ही काम करते हैं: check आपके function से पहले चलता है, इसलिए भूलने का सवाल नहीं।

असली उदाहरण 4: lru_cache से built-in caching

Python – lru_cache.py
from functools import lru_cache

calls = 0

@lru_cache(maxsize=None)
def fib(n):
    global calls
    calls += 1
    return n if n < 2 else fib(n - 1) + fib(n - 2)

print(fib(35))
print("function calls:", calls)
print(fib.cache_info())
9227465 function calls: 36 CacheInfo(hits=33, misses=36, maxsize=None, currsize=36)

Cache के बिना fib(35) लगभग 3 करोड़ calls करता है; cache के साथ सिर्फ़ 36। Caching सिर्फ़ pure functions पर लगाएँ जिनका result केवल arguments पर निर्भर हो।

कई decorators एक साथ: क्रम मायने रखता है

Python – stacking.py
import functools

def bold(func):
    @functools.wraps(func)
    def wrapper():
        return "<b>" + func() + "</b>"
    return wrapper

def italic(func):
    @functools.wraps(func)
    def wrapper():
        return "<i>" + func() + "</i>"
    return wrapper

@bold
@italic
def title():
    return "Result 2026"

print(title())   # same as bold(italic(title))
<b><i>Result 2026</i></b>

Function के सबसे पास वाला decorator पहले लगता है। Stack को नीचे से ऊपर पढ़ें।

आम ग़लतियाँ

ग़लतीक्या होता हैसुधार
Wrapper में return result भूलनाFunction None लौटाता हैमूल result लौटाएँ
बिना arguments वाले decorator पर @timer()TypeError: missing func@timer लिखें; brackets सिर्फ़ decorator factory में
functools.wraps नहींLogs में ग़लत नाम, Flask “endpoint overwriting” errorहमेशा @functools.wraps(func)
समय या database पढ़ने वाले function को cache करनापुराने, ग़लत जवाबसिर्फ़ pure functions cache करें

अभ्यास

  1. @count_calls लिखें जो बताए कि function कितनी बार चला।
  2. @validate_positive लिखें जो कोई number argument negative होने पर ValueError दे।
  3. @cache_for(seconds) लिखें जो result सिर्फ़ दिए गए समय तक याद रखे (time.time() इस्तेमाल करें)।
  4. @timer और @log_call साथ लगाकर छपे क्रम को समझाइए।

सारांश

  • Decorator एक function लेकर extra काम वाला नया function लौटाता है।
  • Function के ऊपर @name का मतलब func = name(func)।
  • *args, **kwargs लें, result लौटाएँ और functools.wraps लगाएँ।
  • Settings चाहिए? एक बाहरी function जोड़ें – decorator factory।
  • आम उपयोग: logging, timing, retries, permissions, caching, routing।

अक्सर पूछे जाने वाले प्रश्न (FAQ)

क्या decorators सिर्फ़ functions के लिए हैं?
नहीं। ये methods और classes पर भी काम करते हैं। @property, @classmethod और @staticmethod classes के अंदर इस्तेमाल होने वाले decorators हैं, और @dataclass जैसा class decorator class लेकर बदली हुई class लौटाता है।
क्या decorators code धीमा करते हैं?
हर call में एक extra function call होती है, जो कुछ सौ nanoseconds है। Database या network के काम की तुलना में यह नगण्य है। lru_cache तो code को बहुत तेज़ कर सकता है।
क्या interviews में decorator पूछा जाता है?
हाँ, बहुत बार। Timing या logging decorator लिखने, closures और functools.wraps समझाने, और arguments लेने वाला decorator लिखने के लिए तैयार रहें।
← Back to Python Tutorial
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

💻 लाइव कोड एडिटर

इस पेज के प्रोग्राम यहीं तैयार हैं — चलाएँ, बदलें और सीखें। कुछ भी इंस्टॉल किए बिना।
OneCompiler द्वारा संचालित। कोड एडिटर में अपने आप आ जाता है — Run दबाकर आउटपुट देखें। अगर एडिटर न खुले तो नए टैब में खोलें.
अगला topicIterators और Generators आपकी प्रगति: 21 / 66 (32%) · Lesson 22 / 66 आगे बढ़ें →

यह lesson कैसा लगा?

आपकी राय से हम content और बेहतर बनाते हैं।

अपना review और सुझाव लिखें (वैकल्पिक)

Review approve होने के बाद आपका नाम और शहर इसके साथ public दिख सकते हैं। Email या phone न लिखें।

▶ CodingEasily on YouTube

Video से सीखें – आसान Hindi में

चुनी हुई video: RDBMS भाग 3 – Class XI Commerce IT

▶ Channel subscribe करें