← Back

Home › Hindi › Python decorator Hindi में

Python Decorator — @ का असली मतलब और काम के examples

🌐 यह page Hindi में है · Read the English functions guide →

@ असल में क्या हैfunctools.wraps ज़रूरी हैArguments वाले decorator3 काम के examples

Decorator असल में क्या है

Decorator एक function है जो दूसरे function को लेता है और उसे बिना बदले extra behaviour देकर नया function लौटा देता है। @name सिर्फ एक shortcut है — नीचे दोनों बराबर हैं:

def shout(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        print("हो गया!")
        return result
    return wrapper

@shout
def greet(name):
    return f"नमस्ते {name}"

# यही चीज़ बिना @ के:
def greet2(name):
    return f"नमस्ते {name}"
greet2 = shout(greet2)          # @shout का पूरा मतलब यही एक line है

print(greet("Asha"))

तो decorator में कोई जादू नहीं है: यह function को function से बदलना है। तीन हिस्से याद रखो — बाहरी function decorator को लेता है, अंदर वाला wrapper असली काम करता है, और return wrapper नया function वापस देता है।

functools.wraps — यह मत भूलना

wrapper लपेटने के बाद असली function की पहचान खो जाती है — नाम, docstring, सब:

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

@shout
def greet(name):
    '''नमस्कार कहता है।'''
    return name

print(greet.__name__)        # 'wrapper'  — असली नाम खो गया!
print(greet.__doc__)         # None

Fix एक line का है, और हर असली decorator में होना चाहिए:

from functools import wraps

def shout(func):
    @wraps(func)               # नाम, docstring, signature सब बचा लेता है
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@shout
def greet(name):
    '''नमस्कार कहता है।'''
    return name

print(greet.__name__)        # 'greet'  ✅
print(greet.__doc__)         # 'नमस्कार कहता है।' ✅

@wraps के बिना debugging बहुत मुश्किल हो जाती है — traceback में हर जगह wrapper दिखता है।

3 decorator जो रोज़ काम आते हैं

import time
from functools import wraps

# 1. कितना समय लगा — सबसे useful decorator
def timing(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        try:
            return func(*args, **kwargs)
        finally:
            print(f"{func.__name__} ने {time.perf_counter() - start:.4f}s लिया")
    return wrapper

# 2. हर call log करना
def log(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"-> {func.__name__}{args} {kwargs}")
        return func(*args, **kwargs)
    return wrapper

# 3. कितनी बार call हुआ
def counted(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        wrapper.calls += 1
        return func(*args, **kwargs)
    wrapper.calls = 0
    return wrapper

@timing
@log
def work(n):
    return sum(range(n))

work(1000)
print(work.calls)

वह stacking भी समझ लो: @timing ऊपर और @log नीचे है, तो पहले log लपेटता है और उसके बाद timing — यानी ऊपर वाला सबसे बाहर चलता है।

Arguments वाला decorator

अगर decorator को खुद setting लेनी हो (जैसे @retry(times=3)), तो एक level और गहरा जाना पड़ता है:

def retry(times=3):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            last = None
            for attempt in range(1, times + 1):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    last = e
                    print(f"कोशिश {attempt} नाकाम: {e}")
            raise last
        return wrapper
    return decorator

@retry(times=2)
def flaky():
    import random
    if random.random() < 0.7:
        raise ValueError("अभी नहीं")
    return "चल गया"

याद रखो: @retry(times=2) में parentheses हैं, इसलिए retry(times=2) पहले चलकर decorator लौटाता है। @retry और @retry() अलग-अलग चीज़ें हैं।

Common गलतियाँ

  1. @wraps भूल जाना — नाम और docstring खो जाते हैं, traceback बेकार हो जाता है।
  2. return func(...) भूल जाना — wrapper None लौटाएगा और caller को कुछ नहीं मिलेगा। यह सबसे common decorator bug है।
  3. *args, **kwargs के बिना wrapper — decorator सिर्फ उन्हीं functions पर चलेगा जिनका signature मेल खाता है।
  4. Decorator में भारी काम — decorator import/definition के वक्त एक बार चलता है, हर call पर नहीं। Setup वहाँ रखो, असली काम wrapper में।

🛠️ Practice करो (free, browser में)

पढ़ना काफी नहीं — यही bug खुद fix करके देखो। नीचे के problems browser में ही चलते हैं, कोई install नहीं, कोई login नहीं।

सारे free problems देखो →

अक्सर पूछे जाने वाले सवाल

Decorator असल में क्या करता है?

यह एक function को लेता है और नया function लौटाता है जो पुराने को लपेटकर extra काम करता है। @name सिर्फ shortcut है — @shout के ऊपर लिखना और greet = shout(greet) लिखना बिल्कुल बराबर है। कोई जादू नहीं, सिर्फ function को function से बदलना।

functools.wraps क्यों ज़रूरी है?

क्योंकि उसके बिना लपेटे गए function का नाम 'wrapper' हो जाता है और docstring None — जिससे traceback और help() बेकार हो जाते हैं। @wraps(func) असली function का नाम, docstring और signature नए wrapper पर कॉपी कर देता है। हर असली decorator में यह होना चाहिए।

मेरा decorated function None क्यों लौटा रहा है?

क्योंकि wrapper में return func(*args, **kwargs) लिखना भूल गए। Wrapper का return ही caller को मिलता है; अगर wrapper कुछ return नहीं करता तो caller को None मिलेगा, भले ही असली function सही value बना रहा हो।

Decorator कब चलता है — definition पर या हर call पर?

दोनों हिस्से अलग वक्त चलते हैं। बाहरी decorator function import/definition के वक्त एक बार चलता है, और wrapper हर call पर। इसलिए कोई भी setup decorator के body में रखो और असली काम wrapper के अंदर।

आगे पढ़ो