Kodokon kodokon.com

डेकोरेटर और उच्च-क्रम फ़ंक्शन

फ़ंक्शन को प्रथम-श्रेणी ऑब्जेक्ट के रूप में इस्तेमाल करके मज़बूत, पैरामीटर-योग्य और पारदर्शी डेकोरेटर लिखें।

10 मिनट · 3 प्रश्न

इस पाठ को Kodokon में खोलें

Python में, फ़ंक्शन बाकी सबकी तरह एक ऑब्जेक्ट है: आप उसे किसी वेरिएबल को असाइन कर सकते हैं, आर्गुमेंट के रूप में पास कर सकते हैं, लौटा सकते हैं। एक उच्च-क्रम फ़ंक्शन कोई फ़ंक्शन लेता है या लौटाता है - sorted(data, key=...) ऐसा ही एक है। इसमें क्लोज़र जोड़ दीजिए, जहाँ भीतरी फ़ंक्शन बाहरी फ़ंक्शन के वेरिएबल को कैप्चर करता है और उसके लौटने के बाद भी उन्हें ज़िंदा रखता है, और आपके पास डेकोरेटर की सारी सामग्री आ जाती है।

PYTHON
def make_multiplier(factor):
    def multiply(value):
        return value * factor
    return multiply

double = make_multiplier(2)
triple = make_multiplier(3)
print(double(10), triple(10))  # 20 30
एक क्लोज़र: multiply, factor को कैप्चर करता है

एक डेकोरेटर ऐसा फ़ंक्शन है जो कोई फ़ंक्शन लेता है और दूसरा लौटाता है - आमतौर पर एक wrapper, जो कॉल के इर्द-गिर्द व्यवहार जोड़ता है। def slow_sum के ऊपर लिखा @timed सिंटैक्स ठीक-ठीक slow_sum = timed(slow_sum) का सिंटैक्टिक शुगर है। रैपर सिग्नेचर से बेपरवाह रहने के लिए *args, kwargs स्वीकार करता है, और डेकोरेट किए गए फ़ंक्शन का परिणाम लौटाता** है - इसे भूल जाना एक क्लासिक गलती है जो हर रिटर्न वैल्यू को None में बदल देती है।

PYTHON
import functools
import time

def timed(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        delay = time.perf_counter() - start
        print(f"{func.__name__}: {delay:.4f}s")
        return result
    return wrapper

@timed
def slow_sum(n):
    return sum(range(n))

print(slow_sum(1_000_000))
समय मापने वाला एक डेकोरेटर, प्रोडक्शन के लिए तैयार

किसी डेकोरेटर को पैरामीटर देने के लिए (@repeat(times=3)), आपको एक और स्तर चाहिए: एक फैक्ट्री जो पैरामीटर लेती है और डेकोरेटर लौटाती है, जो बदले में रैपर लौटाता है। तीन नेस्टेड फ़ंक्शन - लचीलेपन की यही कीमत है। यदि स्टेट जटिल हो जाए, तो __call__ मेथड वाली एक क्लास अक्सर अधिक पठनीय होती है। डेकोरेटर को अनुप्रस्थ सरोकारों के लिए बचाकर रखें: लॉगिंग, कैशिंग, पुनःप्रयास, एक्सेस नियंत्रण। जो डेकोरेटर बिज़नेस लॉजिक बदल देता है, वह पाठक से सबसे ज़रूरी बात छिपा देता है।

PYTHON
import functools

def repeat(times):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            result = None
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(times=3)
def greet(name):
    print(f"Hello {name}")

greet("Ada")
पैरामीटर वाला डेकोरेटर: फैक्ट्री, डेकोरेटर, रैपर

ज्ञान जांच

सुनिश्चित करें कि आपको इस पाठ के मुख्य बिंदु याद हैं।

  1. def slow_sum के ऊपर रखा गया @timed सिंटैक्स किसके समतुल्य है?
    • timed(slow_sum())
    • slow_sum = timed(slow_sum)
    • slow_sum.timed = True
  2. @functools.wraps किस समस्या का समाधान करता है?
    • यह डेकोरेट किए गए फ़ंक्शन की कॉल को तेज़ करता है
    • यह डेकोरेट किए गए फ़ंक्शन का नाम और docstring बनाए रखता है
    • यह डेकोरेटर को क्लास मेथड के अनुकूल बनाता है
  3. @repeat(times=3) में, कॉल repeat(times=3) क्या लौटाती है?
    • डेकोरेट किए गए फ़ंक्शन का परिणाम
    • एक डेकोरेटर, जो फ़ंक्शन लेने को तैयार है
    • सीधे अंतिम रैपर
    • तीन परिणामों की एक लिस्ट