जब आप एक डेकोरेटर का उपयोग करते हैं, तो आप एक फ़ंक्शन को दूसरे के साथ बदल रहे हैं। दूसरे शब्दों में, यदि आपके पास एक डेकोरेटर है
def logged(func):
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
फिर जब आप कहेंगे
@logged
def f(x):
"""does some math"""
return x + x * x
यह कहने के समान ही है
def f(x):
"""does some math"""
return x + x * x
f = logged(f)
और आपके फ़ंक्शन fको फ़ंक्शन के साथ बदल दिया जाता है with_logging। दुर्भाग्य से, इसका मतलब है कि यदि आप कहते हैं
print(f.__name__)
यह प्रिंट होगा with_loggingक्योंकि यह आपके नए फ़ंक्शन का नाम है। वास्तव में, यदि आप डॉकस्ट्रिंग को देखते हैं f, तो यह रिक्त होगा क्योंकि with_loggingइसमें डॉकस्ट्रिंग नहीं है, और इसलिए आपके द्वारा लिखा गया डॉकस्ट्रिंग अब नहीं होगा। इसके अलावा, यदि आप उस फ़ंक्शन के लिए pydoc परिणाम को देखते हैं, तो इसे एक तर्क के रूप में सूचीबद्ध नहीं किया जाएगा x; इसके बजाय इसे लेने के रूप में सूचीबद्ध किया जाएगा *argsऔर **kwargsक्योंकि with_log लेता है।
यदि एक डेकोरेटर का उपयोग हमेशा किसी फ़ंक्शन के बारे में इस जानकारी को खोने का मतलब होता है, तो यह एक गंभीर समस्या होगी। इसलिए हमारे पास है functools.wraps। यह एक डेकोरेटर में उपयोग किए जाने वाले फ़ंक्शन को लेता है और फ़ंक्शन नाम, डॉकस्ट्रिंग, तर्क सूची इत्यादि पर कॉपी करने की कार्यक्षमता को जोड़ता है और चूंकि wrapsखुद एक डेकोरेटर है, निम्न कोड सही काम करता है:
from functools import wraps
def logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logged
def f(x):
"""does some math"""
return x + x * x
print(f.__name__) # prints 'f'
print(f.__doc__) # prints 'does some math'