मुख्य सामग्री पर जाएं
मॉड्यूल 9 · पाठ 4 का 4पाठ्यक्रम में 36/36~14 min
मॉड्यूल पाठ (4/4)

डेकोरेटर: फ़ंक्शन जो फ़ंक्शन को संशोधित करते हैं

डेकोरेटर एक फ़ंक्शन है जो एक अन्य फ़ंक्शन लेता है और एक लौटाता है इसका "सजाया हुआ" संस्करण। यह व्यवहार जोड़ने का एक सशक्त तरीका है (लॉगिंग, टाइमिंग, कैशिंग, पुनः प्रयास, सत्यापन) के मुख्य भाग को छुए बिना मूल कार्य.

मूल्यों के रूप में कार्य करता है

पायथन में, फ़ंक्शन ऑब्जेक्ट हैं: आप उन्हें पास कर सकते हैं, उन्हें वापस कर सकते हैं, उन्हें असाइन कर सकते हैं।

Python
def saluta():
    print("ciao")

f = saluta   # NIENTE parentesi: assegno la funzione
f()          # 'ciao'

एक न्यूनतम सज्जाकार

Python
def log(func):
    def wrapper(*args, **kwargs):
        print(f"chiamo {func.__name__}")
        risultato = func(*args, **kwargs)
        print(f"ho finito {func.__name__}")
        return risultato
    return wrapper

def somma(a, b):
    return a + b

somma = log(somma)   # ora somma è "wrapper"
somma(2, 3)
# chiamo somma
# ho finito somma
# 5

@decorator सिंटैक्स

असाइनमेंट somma = log(somma) को @ के साथ अधिक सुंदर ढंग से लिखा गया है:

Python
@log
def somma(a, b):
    return a + b

यह बिल्कुल वैसी ही बात है। उपरोक्त परिभाषा @log इसके समतुल्य है: "जैसे ही यह फ़ंक्शन परिभाषित हो जाए, इसे log(function) से बदल दें"।

*args, **kwargs: कोई भी हस्ताक्षर स्वीकार करें

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

*args स्थितीय तर्क, **kwargs कीवर्ड तर्क एकत्र करता है। उन्होंने जाने दिया आप ऐसे रैपर लिखते हैं जो किसी भी फ़ंक्शन के साथ काम करते हैं।

functools.wraps: मेटाडेटा को सुरक्षित रखें

wraps के बिना, सजाया गया फ़ंक्शन __name__, __doc__ खो देता है, संकेत:

Python
from functools import wraps

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

उदाहरण: @timeit

Python
from functools import wraps
import time

def timeit(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        t0 = time.perf_counter()
        risultato = func(*args, **kwargs)
        dt = time.perf_counter() - t0
        print(f"{func.__name__} ha impiegato {dt*1000:.2f} ms")
        return risultato
    return wrapper

@timeit
def somma_grande():
    return sum(range(10**6))

somma_grande()

stdlib से सज्जाकार

Python
from functools import lru_cache

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

fib(100)  # istantaneo grazie alla cache
  • @lru_cache - शुद्ध फ़ंक्शन के परिणामों को याद रखता है।
  • @property - एक विधि को एक विशेषता के रूप में उजागर करता है (OOP मॉड्यूल में देखा गया)।
  • @staticmethod, @classmethod — self को पारित करने का तरीका बदलें।

तर्क-वितर्क के साथ सज्जाकार

सज्जाकार भी तर्क स्वीकार कर सकते हैं. इसे लागू करने के लिए, आपको नेस्टेड फ़ंक्शंस के तीन स्तर लिखने होंगे: सबसे बाहरी फ़ंक्शन डेकोरेटर के तर्क प्राप्त करता है, मध्य फ़ंक्शन डेकोरेटेड फ़ंक्शन प्राप्त करता है, और सबसे आंतरिक फ़ंक्शन (wrapper) कॉल के दौरान डेकोरेटर फ़ंक्शन को दिए गए वास्तविक तर्क प्राप्त करता है।

खुद कोशिश करना

व्यायाम#python.m9.l4.e1
प्रयास: 0लोड हो रहा है...

एक डेकोरेटर `डबल_रिजल्ट` लिखें जो डेकोरेटेड फ़ंक्शन को कॉल करता है और उसका परिणाम देता है * 2. इसे फ़ंक्शन `f(x)` पर लागू करें जो x + 1 लौटाता है। `f(10)` का मूल्यांकन करें।

संपादक लोड हो रहा है...
संकेत दिखाएँ

रैपर func को कॉल करता है और परिणाम को 2 से गुणा करके लौटाता है।

3 प्रयासों के बाद समाधान उपलब्ध है

व्यायाम की समीक्षा करें

व्यायाम#python.m9.l4.e2
प्रयास: 0लोड हो रहा है...

पुनरावर्ती फ़ाइब(एन) फ़ंक्शन को तेज़ करने के लिए functools.lru_cache का उपयोग करें। फ़ाइब(30) की गणना करें और `r` को असाइन करें। `r` का मूल्यांकन करें.

संपादक लोड हो रहा है...
संकेत दिखाएँ

@lru_cache(maxsize=None) डीईएफ़ से ऊपर।

3 प्रयासों के बाद समाधान उपलब्ध है

अतिरिक्त चुनौती

व्यायाम#python.m9.l4.e3
प्रयास: 0लोड हो रहा है...

Define a decorator `double_result` that doubles (multiplies by 2) the return value of the decorated function. Apply the decorator to the function `def sum_nums(a, b): return a + b`. Finally, evaluate `sum_nums(3, 4)`.

संपादक लोड हो रहा है...
संकेत दिखाएँ

रैपर func(*args, **kwargs) को कॉल करता है और परिणाम को 2 से गुणा करता है।

3 प्रयासों के बाद समाधान उपलब्ध है