मुझे पता है कि यह सवाल पुराना है, लेकिन कुछ टिप्पणियां नई हैं, और जबकि सभी व्यवहार्य समाधान अनिवार्य रूप से समान हैं, उनमें से अधिकांश बहुत साफ या पढ़ने में आसान नहीं हैं।
जैसा कि थोबे का जवाब कहता है, दोनों मामलों को संभालने का एकमात्र तरीका दोनों परिदृश्यों की जांच करना है। सबसे आसान तरीका यह है कि यह देखने के लिए कि क्या कोई एकल तर्क है और यह कॉलबेब है (नोट: अतिरिक्त चेक आवश्यक होगा यदि आपका डेकोरेटर केवल 1 तर्क लेता है और यह कॉल करने योग्य ऑब्जेक्ट होता है):
def decorator(*args, **kwargs):
if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
else:
पहले मामले में, आप वही करते हैं जो कोई भी सामान्य डेकोरेटर करता है, फ़ंक्शन में पारित का एक संशोधित या लिपटे संस्करण लौटाता है।
दूसरे मामले में, आप एक 'नए' डेकोरेटर को लौटाते हैं, जो किसी तरह से पास की गई जानकारी को * आर्ग, ** क्वार्ग्स के साथ प्रयोग करता है।
यह ठीक है और सभी है, लेकिन आपके द्वारा किए गए हर डेकोरेटर के लिए इसे लिखना बहुत कष्टप्रद हो सकता है और उतना साफ नहीं। इसके बजाय, यह अच्छा होगा कि हम अपने डेकोरेटर्स को आटोमैटिकली मॉडिफाई कर सकें, उन्हें दोबारा लिखे बिना ... लेकिन यही डेकोरेटर्स किस लिए हैं!
निम्नलिखित डेकोरेटर डेकोरेटर का उपयोग करके, हम अपने डेकोरेटर्स को हटा सकते हैं ताकि उनका उपयोग तर्कों के साथ या बिना किया जा सके:
def doublewrap(f):
'''
a decorator decorator, allowing the decorator to be used as:
@decorator(with, arguments, and=kwargs)
or
@decorator
'''
@wraps(f)
def new_dec(*args, **kwargs):
if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
return f(args[0])
else:
return lambda realf: f(realf, *args, **kwargs)
return new_dec
अब, हम @ सज्जाकार के साथ अपने डेकोरेटर को सजा सकते हैं, और वे बिना किसी तर्क के साथ और बिना तर्क के काम करेंगे:
मैंने ऊपर उल्लेख किया है, लेकिन यहां दोहराना चाहिए, इस डेकोरेटर में चेक उन तर्कों के बारे में एक धारणा बनाता है जो एक डेकोरेटर प्राप्त कर सकता है (अर्थात यह एक एकल, कॉल करने योग्य तर्क प्राप्त नहीं कर सकता है)। चूंकि अब हम इसे किसी भी जनरेटर के लिए लागू कर रहे हैं, इसलिए इसे विरोधाभास होने पर इसे ध्यान में रखा जाना चाहिए या संशोधित किया जाना चाहिए।
निम्नलिखित इसके उपयोग को प्रदर्शित करता है:
def test_doublewrap():
from util import doublewrap
from functools import wraps
@doublewrap
def mult(f, factor=2):
'''multiply a function's return value'''
@wraps(f)
def wrap(*args, **kwargs):
return factor*f(*args,**kwargs)
return wrap
@mult
def f(x, y):
return x + y
@mult(3)
def f2(x, y):
return x*y
@mult(factor=5)
def f3(x, y):
return x - y
assert f(2,3) == 10
assert f2(2,5) == 30
assert f3(8,1) == 5*7
@redirect_outputउल्लेखनीय रूप से एकरूप है। मेरा सुझाव है कि यह एक बुरा विचार है। पहले रूप का उपयोग करें और अपने जीवन को सरल बनाएं।