एक डेकोरेटर एक फ़ंक्शन में लेता है, कुछ कार्यक्षमता जोड़ता है और इसे वापस करता है। इस ट्यूटोरियल में, आप सीखेंगे कि आप एक डेकोरेटर कैसे बना सकते हैं और आपको इसका उपयोग क्यों करना चाहिए।
पायथन में सज्जाकार
पायथन में एक दिलचस्प विशेषता है जिसे मौजूदा कोड में कार्यक्षमता जोड़ने के लिए सज्जाकार कहा जाता है ।
इसे मेटाप्रोग्रामिंग भी कहा जाता है क्योंकि कार्यक्रम का एक हिस्सा संकलन के समय कार्यक्रम के दूसरे भाग को संशोधित करने का प्रयास करता है।
सज्जाकार सीखने के लिए आवश्यक शर्तें
सज्जाकारों के बारे में समझने के लिए, हमें पहले पायथन में कुछ बुनियादी बातों को जानना चाहिए।
हमें इस तथ्य के साथ सहज होना चाहिए कि पायथन में सब कुछ (हाँ! यहां तक कि कक्षाएं), वस्तुएं हैं। जिन नामों को हम परिभाषित करते हैं, वे इन वस्तुओं के लिए बस पहचानकर्ता हैं। फ़ंक्शंस कोई अपवाद नहीं हैं, वे ऑब्जेक्ट भी हैं (विशेषताओं के साथ)। विभिन्न विभिन्न नाम एक ही फ़ंक्शन ऑब्जेक्ट के लिए बाध्य हो सकते हैं।
यहाँ एक उदाहरण है।
def first(msg): print(msg) first("Hello") second = first second("Hello")
आउटपुट
हैलो हैलो
जब आप कोड चलाते हैं, तो दोनों कार्य करते हैं first
और second
समान आउटपुट देते हैं। यहां, एक ही फ़ंक्शन ऑब्जेक्ट के नाम first
और second
संदर्भ।
अब चीजें अजीब होने लगती हैं।
फ़ंक्शन को किसी अन्य फ़ंक्शन के लिए तर्क के रूप में पारित किया जा सकता है।
आप की तरह इस्तेमाल किया कार्यों है map
, filter
और reduce
अजगर में है, तो आप पहले से ही इस बारे में पता।
ऐसे कार्य जो अन्य कार्यों को तर्क के रूप में लेते हैं, उन्हें उच्च क्रम फ़ंक्शन भी कहा जाता है । यहाँ इस तरह के एक समारोह का एक उदाहरण है।
def inc(x): return x + 1 def dec(x): return x - 1 def operate(func, x): result = func(x) return result
हम फ़ंक्शन को निम्नानुसार लागू करते हैं।
>>> operate(inc,3) 4 >>> operate(dec,3) 2
इसके अलावा, एक फ़ंक्शन दूसरे फ़ंक्शन को वापस कर सकता है।
def is_called(): def is_returned(): print("Hello") return is_returned new = is_called() # Outputs "Hello" new()
आउटपुट
नमस्कार
यहां, is_returned()
एक नेस्टेड फ़ंक्शन है जिसे परिभाषित किया जाता है और हर बार जब हम कॉल करते हैं तो वापस लौटा दिया जाता है is_called()
।
अंत में, हमें पायथन में क्लोजर के बारे में पता होना चाहिए।
डेकोरेटर्स को वापस मिल रहा है
कार्य और पद्धतियों को बुलाया जाता प्रतिदेय के रूप में वे कहा जा सकता है।
वास्तव में, विशेष __call__()
विधि को लागू करने वाली किसी भी वस्तु को कॉल करने योग्य कहा जाता है। तो, सबसे बुनियादी अर्थ में, एक डेकोरेटर एक कॉल करने योग्य है जो कॉल करने योग्य रिटर्न देता है।
मूल रूप से, एक डेकोरेटर एक फ़ंक्शन में लेता है, कुछ कार्यक्षमता जोड़ता है और इसे वापस करता है।
def make_pretty(func): def inner(): print("I got decorated") func() return inner def ordinary(): print("I am ordinary")
जब आप शेल में निम्नलिखित कोड चलाते हैं,
>>> ordinary() I am ordinary >>> # let's decorate this ordinary function >>> pretty = make_pretty(ordinary) >>> pretty() I got decorated I am ordinary
ऊपर दिखाए गए उदाहरण में, make_pretty()
एक डेकोरेटर है। असाइनमेंट चरण में:
pretty = make_pretty(ordinary)
समारोह ordinary()
को सजाया गया और लौटे फ़ंक्शन को नाम दिया गया pretty
।
हम देख सकते हैं कि डेकोरेटर फ़ंक्शन ने मूल फ़ंक्शन में कुछ नई कार्यक्षमता जोड़ी है। यह एक उपहार पैक करने के समान है। डेकोरेटर एक रैपर के रूप में कार्य करता है। जिस वस्तु को सजाया गया है उसकी प्रकृति (वास्तविक उपहार अंदर) नहीं बदलती है। लेकिन अब, यह सुंदर लग रहा है (क्योंकि यह सजाया गया)।
आम तौर पर, हम एक फंक्शन को सजाते हैं और इसे पुन: असाइन करते हैं,
ordinary = make_pretty(ordinary).
यह एक सामान्य निर्माण है और इस कारण से, पायथन में इसे सरल बनाने के लिए एक वाक्यविन्यास है।
हम @
डेकोरेटर फ़ंक्शन के नाम के साथ प्रतीक का उपयोग कर सकते हैं और इसे फ़ंक्शन की परिभाषा के ऊपर सजा सकते हैं। उदाहरण के लिए,
@make_pretty def ordinary(): print("I am ordinary")
के बराबर है
def ordinary(): print("I am ordinary") ordinary = make_pretty(ordinary)
यह डेकोरेटर्स को लागू करने के लिए सिर्फ एक सिंटैक्टिक शुगर है।
पैरामीटर के साथ सजा कार्य
उपरोक्त सज्जाकार सरल था और यह केवल उन कार्यों के साथ काम करता था जिनमें कोई पैरामीटर नहीं था। क्या होगा अगर हमारे पास ऐसे कार्य हैं जो पैरामीटर में हैं:
def divide(a, b): return a/b
इस फ़ंक्शन के दो पैरामीटर हैं, ए और बी। हम जानते हैं कि यह एक त्रुटि देगा यदि हम b को 0 के रूप में पास करते हैं।
>>> divide(2,5) 0.4 >>> divide(2,0) Traceback (most recent call last):… ZeroDivisionError: division by zero
अब इस मामले की जांच के लिए एक डेकोरेटर बनाते हैं जो त्रुटि का कारण होगा।
def smart_divide(func): def inner(a, b): print("I am going to divide", a, "and", b) if b == 0: print("Whoops! cannot divide") return return func(a, b) return inner @smart_divide def divide(a, b): print(a/b)
None
त्रुटि स्थिति उत्पन्न होने पर यह नया कार्यान्वयन वापस आ जाएगा ।
>>> divide(2,5) I am going to divide 2 and 5 0.4 >>> divide(2,0) I am going to divide 2 and 0 Whoops! cannot divide
इस तरीके से, हम उन कार्यों को सजा सकते हैं जो पैरामीटर लेते हैं।
एक गहरी पर्यवेक्षक नोटिस करेगा कि inner()
डेकोरेटर के अंदर नेस्टेड फ़ंक्शन के पैरामीटर उसी प्रकार हैं जैसे कि यह फ़ंक्शन के मापदंडों को सजाता है। इसे ध्यान में रखते हुए, अब हम सामान्य सज्जाकार बना सकते हैं जो किसी भी संख्या में मापदंडों के साथ काम करते हैं।
In Python, this magic is done as function(*args, **kwargs)
. In this way, args
will be the tuple of positional arguments and kwargs
will be the dictionary of keyword arguments. An example of such a decorator will be:
def works_for_all(func): def inner(*args, **kwargs): print("I can decorate any function") return func(*args, **kwargs) return inner
Chaining Decorators in Python
Multiple decorators can be chained in Python.
This is to say, a function can be decorated multiple times with different (or same) decorators. We simply place the decorators above the desired function.
def star(func): def inner(*args, **kwargs): print("*" * 30) func(*args, **kwargs) print("*" * 30) return inner def percent(func): def inner(*args, **kwargs): print("%" * 30) func(*args, **kwargs) print("%" * 30) return inner @star @percent def printer(msg): print(msg) printer("Hello")
Output
****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Hello %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************************
The above syntax of,
@star @percent def printer(msg): print(msg)
is equivalent to
def printer(msg): print(msg) printer = star(percent(printer))
The order in which we chain decorators matter. If we had reversed the order as,
@percent @star def printer(msg): print(msg)
The output would be:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ****************************** Hello ****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%