मॉड्यूल पाठ (4/4)
डेकोरेटर: फ़ंक्शन जो फ़ंक्शन को संशोधित करते हैं
डेकोरेटर एक फ़ंक्शन है जो एक अन्य फ़ंक्शन लेता है और एक लौटाता है इसका "सजाया हुआ" संस्करण। यह व्यवहार जोड़ने का एक सशक्त तरीका है (लॉगिंग, टाइमिंग, कैशिंग, पुनः प्रयास, सत्यापन) के मुख्य भाग को छुए बिना मूल कार्य.
मूल्यों के रूप में कार्य करता है
पायथन में, फ़ंक्शन ऑब्जेक्ट हैं: आप उन्हें पास कर सकते हैं, उन्हें वापस कर सकते हैं, उन्हें असाइन कर सकते हैं।
def saluta():
print("ciao")
f = saluta # NIENTE parentesi: assegno la funzione
f() # 'ciao'एक न्यूनतम सज्जाकार
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) को @ के साथ अधिक सुंदर ढंग से लिखा गया है:
@log
def somma(a, b):
return a + bयह बिल्कुल वैसी ही बात है। उपरोक्त परिभाषा @log इसके समतुल्य है:
"जैसे ही यह फ़ंक्शन परिभाषित हो जाए, इसे log(function) से बदल दें"।
*args, **kwargs: कोई भी हस्ताक्षर स्वीकार करें
def wrapper(*args, **kwargs):
return func(*args, **kwargs)*args स्थितीय तर्क, **kwargs कीवर्ड तर्क एकत्र करता है। उन्होंने जाने दिया
आप ऐसे रैपर लिखते हैं जो किसी भी फ़ंक्शन के साथ काम करते हैं।
functools.wraps: मेटाडेटा को सुरक्षित रखें
wraps के बिना, सजाया गया फ़ंक्शन __name__, __doc__ खो देता है, संकेत:
from functools import wraps
def log(func):
@wraps(func)
def wrapper(*args, **kwargs):
...
return func(*args, **kwargs)
return wrapperउदाहरण: @timeit
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 से सज्जाकार
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) कॉल के दौरान डेकोरेटर फ़ंक्शन को दिए गए वास्तविक तर्क प्राप्त करता है।
खुद कोशिश करना
एक डेकोरेटर `डबल_रिजल्ट` लिखें जो डेकोरेटेड फ़ंक्शन को कॉल करता है और उसका परिणाम देता है * 2. इसे फ़ंक्शन `f(x)` पर लागू करें जो x + 1 लौटाता है। `f(10)` का मूल्यांकन करें।
संकेत दिखाएँ
रैपर func को कॉल करता है और परिणाम को 2 से गुणा करके लौटाता है।
3 प्रयासों के बाद समाधान उपलब्ध है
व्यायाम की समीक्षा करें
पुनरावर्ती फ़ाइब(एन) फ़ंक्शन को तेज़ करने के लिए functools.lru_cache का उपयोग करें। फ़ाइब(30) की गणना करें और `r` को असाइन करें। `r` का मूल्यांकन करें.
संकेत दिखाएँ
@lru_cache(maxsize=None) डीईएफ़ से ऊपर।
3 प्रयासों के बाद समाधान उपलब्ध है
अतिरिक्त चुनौती
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 प्रयासों के बाद समाधान उपलब्ध है