यह सर्वविदित है कि निम्नलिखित दो टुकड़े कोड लगभग बराबर हैं:
@dec
def foo():
pass foo = dec(foo)
############################################
foo = dec(foo)
एक सामान्य गलती यह सोचना है कि @
बस सबसे बाएं तर्क को छुपाता है।
@dec(1, 2, 3)
def foo():
pass
###########################################
foo = dec(foo, 1, 2, 3)
डेकोरेटर लिखना बहुत आसान होगा यदि उपरोक्त कैसे @
काम किया जाए। दुर्भाग्य से, इस तरह से चीजें नहीं की जाती हैं।
एक डेकोरेटर पर विचार करें Wait
जो कुछ सेकंड के लिए प्रोग्राम निष्पादन को बाधित करता है। यदि आप प्रतीक्षा-समय में पास नहीं होते हैं, तो डिफ़ॉल्ट मान 1 सेकंड है। उपयोग-मामलों को नीचे दिखाया गया है।
##################################################
@Wait
def print_something(something):
print(something)
##################################################
@Wait(3)
def print_something_else(something_else):
print(something_else)
##################################################
@Wait(delay=3)
def print_something_else(something_else):
print(something_else)
जब Wait
कोई तर्क होता है, जैसे कि @Wait(3)
, तब कुछ और होने से पहले कॉल Wait(3)
को निष्पादित किया जाता है।
अर्थात्, कोड के निम्नलिखित दो टुकड़े समतुल्य हैं
@Wait(3)
def print_something_else(something_else):
print(something_else)
###############################################
return_value = Wait(3)
@return_value
def print_something_else(something_else):
print(something_else)
यह एक समस्या है।
if `Wait` has no arguments:
`Wait` is the decorator.
else: # `Wait` receives arguments
`Wait` is not the decorator itself.
Instead, `Wait` ***returns*** the decorator
एक समाधान नीचे दिखाया गया है:
हम निम्न वर्ग बनाकर शुरू करते हैं DelayedDecorator
:
class DelayedDecorator:
def __init__(i, cls, *args, **kwargs):
print("Delayed Decorator __init__", cls, args, kwargs)
i._cls = cls
i._args = args
i._kwargs = kwargs
def __call__(i, func):
print("Delayed Decorator __call__", func)
if not (callable(func)):
import io
with io.StringIO() as ss:
print(
"If only one input, input must be callable",
"Instead, received:",
repr(func),
sep="\n",
file=ss
)
msg = ss.getvalue()
raise TypeError(msg)
return i._cls(func, *i._args, **i._kwargs)
अब हम इस तरह की बातें लिख सकते हैं:
dec = DelayedDecorator(Wait, delay=4)
@dec
def delayed_print(something):
print(something)
ध्यान दें कि:
dec
एकाधिक तर्कों को स्वीकार नहीं करता है।
dec
केवल लिपटे जाने के लिए फ़ंक्शन स्वीकार करता है।
इंपोर्ट इंस्पेक्शन क्लास PolyArgDecoratorMeta (प्रकार): def कॉल (रुको, * args, ** kwargs): कोशिश करें: arg_count = len (args) अगर (arg_count = 1): if callable (args [0]): SuperClass = निरीक्षण करें। getmro (PolyArgDecoratorMeta) [1] r = सुपरक्लास। कॉल करें (प्रतीक्षा करें, args [0]) और: r = DelayedDecorator (प्रतीक्षा करें, * args, ** kwargs) और: r = DelayedDecorator (प्रतीक्षा करें, * args, ** kwargs): अंत में, पास रिटर्न r
आयात समय वर्ग प्रतीक्षा करें (मेटाक्लास = पॉलीग्रेक्टरटोरेटा): init (i, func, delay = 2): i._func = func i._delay = विलंब
def __call__(i, *args, **kwargs):
time.sleep(i._delay)
r = i._func(*args, **kwargs)
return r
निम्नलिखित दो टुकड़े समतुल्य हैं:
@Wait
def print_something(something):
print (something)
##################################################
def print_something(something):
print(something)
print_something = Wait(print_something)
हम "something"
कंसोल पर बहुत धीरे-धीरे प्रिंट कर सकते हैं , इस प्रकार है:
print_something("something")
#################################################
@Wait(delay=1)
def print_something_else(something_else):
print(something_else)
##################################################
def print_something_else(something_else):
print(something_else)
dd = DelayedDecorator(Wait, delay=1)
print_something_else = dd(print_something_else)
##################################################
print_something_else("something")
अंतिम नोट्स
यह बहुत कोड की तरह लग सकता है, लेकिन आपको कक्षाएं DelayedDecorator
और PolyArgDecoratorMeta
हर बार लिखना नहीं है । एकमात्र कोड आपको व्यक्तिगत रूप से कुछ इस प्रकार लिखना है, जो काफी छोटा है:
from PolyArgDecoratorMeta import PolyArgDecoratorMeta
import time
class Wait(metaclass=PolyArgDecoratorMeta):
def __init__(i, func, delay = 2):
i._func = func
i._delay = delay
def __call__(i, *args, **kwargs):
time.sleep(i._delay)
r = i._func(*args, **kwargs)
return r
execute_complete_reservation
दो पैरामीटर लेता है, लेकिन आप इसे एक पास कर रहे हैं। डेकोरेटर्स अन्य कार्यों के अंदर लपेटने के कार्यों के लिए सिंटैक्टिक शुगर हैं। पूर्ण दस्तावेज़ के लिए docs.python.org/reference/compound_stmts.html#function देखें ।