खोज…


परिचय

डेकोरेटर फ़ंक्शन सॉफ्टवेयर डिज़ाइन पैटर्न हैं। वे गतिशील रूप से किसी फ़ंक्शन, विधि, या वर्ग की कार्यक्षमता को सीधे उपवर्गों का उपयोग किए बिना बदल देते हैं या सजाए गए फ़ंक्शन के स्रोत कोड को बदल देते हैं। जब सही तरीके से उपयोग किया जाता है, तो डेकोरेटर विकास प्रक्रिया में शक्तिशाली उपकरण बन सकते हैं। इस विषय में पायथन में कार्यान्वयन और सज्जाकार कार्यों के अनुप्रयोग शामिल हैं।

वाक्य - विन्यास

  • डेकोर डेकोरेटर_फंक्शन (एफ): पास # डेकोरेटर_फंक्शन नामक डेकोरेटर को परिभाषित करता है

  • @decorator_function
    def सजाया_function (): पास # फ़ंक्शन अब लिपटे (सजाया गया) डेकोरेटर_फंक्शन है

  • @decorator_function = डेकोरेटर_फंक्शन ( @decorator_function ) # यह वाक्यगत चीनी @decorator_function का उपयोग करने के बराबर है

पैरामीटर

पैरामीटर विवरण
सजाया जाने वाला कार्य (लपेटा हुआ)

डेकोरेटर फ़ंक्शन

सज्जाकार अन्य कार्यों या विधियों के व्यवहार को बढ़ाते हैं। कोई भी फ़ंक्शन जो एक फ़ंक्शन को पैरामीटर के रूप में लेता है और एक संवर्धित फ़ंक्शन देता है, को डेकोरेटर के रूप में उपयोग किया जा सकता है।

# This simplest decorator does nothing to the function being decorated. Such
# minimal decorators can occasionally be used as a kind of code markers.
def super_secret_function(f):
    return f

@super_secret_function
def my_function():
    print("This is my secret function.")

@ -प्रोटेशन वाक्यगत शर्करा है जो निम्नलिखित के बराबर है:

my_function = super_secret_function(my_function)

डेकोरेटर कैसे काम करते हैं, इसे समझने के लिए इसे ध्यान में रखना महत्वपूर्ण है। यह "अनसुना" वाक्यविन्यास यह स्पष्ट करता है कि डेकोरेटर फ़ंक्शन एक फ़ंक्शन को तर्क के रूप में क्यों लेता है, और इसे दूसरे फ़ंक्शन को वापस क्यों करना चाहिए। यह यह भी दर्शाता है कि यदि आप एक फ़ंक्शन वापस नहीं करते हैं तो क्या होगा:

def disabled(f):
    """
    This function returns nothing, and hence removes the decorated function
    from the local scope.
    """
    pass

@disabled
def my_function():
    print("This function can no longer be called...")

my_function()
# TypeError: 'NoneType' object is not callable

इस प्रकार, हम आम तौर पर डेकोरेटर के अंदर एक नए फ़ंक्शन को परिभाषित करते हैं और इसे वापस करते हैं। यह नया फ़ंक्शन पहले कुछ ऐसा करेगा जो उसे करने की आवश्यकता है, फिर मूल फ़ंक्शन को कॉल करें, और अंत में वापसी मान को संसाधित करें। इस साधारण डेकोरेटर फ़ंक्शन पर विचार करें जो मूल फ़ंक्शन को प्राप्त होने वाले तर्कों को प्रिंट करता है, फिर उसे कॉल करता है।

#This is the decorator
def print_args(func):
    def inner_func(*args, **kwargs):
        print(args)
        print(kwargs)
        return func(*args, **kwargs) #Call the original function with its arguments.
    return inner_func

@print_args
def multiply(num_a, num_b):
    return num_a * num_b
  
print(multiply(3, 5))
#Output:
# (3,5) - This is actually the 'args' that the function receives.
# {} - This is the 'kwargs', empty because we didn't specify keyword arguments.
# 15 - The result of the function.

डेकोरेटर वर्ग

जैसा कि परिचय में उल्लेख किया गया है, एक डेकोरेटर एक फ़ंक्शन है जिसे इसके व्यवहार को बढ़ाने के लिए दूसरे फ़ंक्शन पर लागू किया जा सकता है। सिंटैक्टिक शुगर निम्नलिखित के बराबर है: my_func = decorator(my_func) । लेकिन क्या होगा अगर decorator एक वर्ग के बजाय था? सिंटैक्स अभी भी काम करेगा, सिवाय इसके कि अब my_func decorator वर्ग के एक उदाहरण के साथ बदल जाता है। यदि यह वर्ग __call__() जादू पद्धति को लागू करता है, तो यह अभी भी my_func का उपयोग करना संभव होगा जैसे कि यह एक फ़ंक्शन था:

class Decorator(object):
    """Simple decorator class."""

    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print('Before the function call.')
        res = self.func(*args, **kwargs)
        print('After the function call.')
        return res

@Decorator
def testfunc():
    print('Inside the function.')

testfunc()
# Before the function call.
# Inside the function.
# After the function call.

ध्यान दें कि एक क्लास डेकोरेटर के साथ सजाए गए फ़ंक्शन को अब टाइप-चेकिंग परिप्रेक्ष्य से "फ़ंक्शन" नहीं माना जाएगा:

import types
isinstance(testfunc, types.FunctionType)
# False
type(testfunc)
# <class '__main__.Decorator'>

सजाने के तरीके

सजाने के तरीकों के लिए आपको एक अतिरिक्त __get__ -method को परिभाषित करने की आवश्यकता है:

from types import MethodType

class Decorator(object):
    def __init__(self, func):
        self.func = func
        
    def __call__(self, *args, **kwargs):
        print('Inside the decorator.')
        return self.func(*args, **kwargs)
    
    def __get__(self, instance, cls):
        # Return a Method if it is called on an instance
        return self if instance is None else MethodType(self, instance)

class Test(object):
    @Decorator
    def __init__(self):
        pass
    
a = Test()

डेकोरेटर के अंदर।

चेतावनी!

क्लास डेकोरेटर केवल एक विशिष्ट फ़ंक्शन के लिए एक उदाहरण प्रस्तुत करते हैं, इसलिए क्लास डेकोरेटर के साथ एक विधि को सजाने से उस क्लास के सभी उदाहरणों के बीच एक ही डेकोरेटर साझा होगा:

from types import MethodType

class CountCallsDecorator(object):
    def __init__(self, func):
        self.func = func
        self.ncalls = 0    # Number of calls of this method
        
    def __call__(self, *args, **kwargs):
        self.ncalls += 1   # Increment the calls counter
        return self.func(*args, **kwargs)
    
    def __get__(self, instance, cls):
        return self if instance is None else MethodType(self, instance)

class Test(object):
    def __init__(self):
        pass
    
    @CountCallsDecorator
    def do_something(self):
        return 'something was done'
    
a = Test()
a.do_something()
a.do_something.ncalls   # 1
b = Test()
b.do_something()
b.do_something.ncalls   # 2

डेकोरेटर बनाना फंक्शन की तरह लग रहा है

डेकोरेटर्स आम तौर पर फंक्शन मेटाडेटा को स्ट्रिप करते हैं क्योंकि वे समान नहीं होते हैं। मेटा-प्रोग्रामिंग का उपयोग गतिशील रूप से फ़ंक्शन मेटाडेटा तक पहुंचने पर यह समस्या पैदा कर सकता है। मेटाडेटा में फ़ंक्शन का डोकस्ट्रिंग्स और उसका नाम भी शामिल है। functools.wraps सजे हुए फंक्शन को रैपर फंक्शन की कई functools.wraps को कॉपी करके ऑरिजनल फंक्शन की तरह बनाते हैं।

from functools import wraps

डेकोरेटर को लपेटने के दो तरीके एक ही चीज को छिपाते हैं जो मूल फ़ंक्शन को सजाया गया है। जब तक आप पहले से ही एक दूसरे का उपयोग नहीं कर रहे हैं, तब तक क्लास संस्करण में फ़ंक्शन संस्करण को पसंद करने का कोई कारण नहीं है।

एक समारोह के रूप में

def decorator(func):
    # Copies the docstring, name, annotations and module to the decorator
    @wraps(func)
    def wrapped_func(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapped_func

@decorator
def test():
    pass

test.__name__

'परीक्षा'

एक वर्ग के रूप में

class Decorator(object):
    def __init__(self, func):
        # Copies name, module, annotations and docstring to the instance.
        self._wrapped = wraps(func)(self)
        
    def __call__(self, *args, **kwargs):
        return self._wrapped(*args, **kwargs)

@Decorator
def test():
    """Docstring of test."""
    pass

test.__doc__

'परीक्षण का डॉकस्ट्रिंग।'

तर्कों के साथ डेकोरेटर (डेकोरेटर फैक्टरी)

एक डेकोरेटर सिर्फ एक तर्क लेता है: सजाया जाने वाला फ़ंक्शन। अन्य तर्कों को पारित करने का कोई तरीका नहीं है।

लेकिन अतिरिक्त तर्क अक्सर वांछित होते हैं। चाल तब एक समारोह बनाने के लिए है जो मनमानी तर्क लेता है और एक डेकोरेटर लौटाता है।

डेकोरेटर कार्य करता है

def decoratorfactory(message):
    def decorator(func):
        def wrapped_func(*args, **kwargs):
            print('The decorator wants to tell you: {}'.format(message))
            return func(*args, **kwargs)
        return wrapped_func
    return decorator

@decoratorfactory('Hello World')
def test():
    pass

test()

डेकोरेटर आपको बताना चाहता है: हैलो वर्ल्ड

महत्वपूर्ण लेख:

ऐसे डेकोरेटर कारखानों के साथ आपको डेकोरेटर को कोष्ठक की एक जोड़ी के साथ कॉल करना होगा :

@decoratorfactory # Without parentheses
def test():
    pass

test()

TypeError: डेकोरेटर () लापता 1 आवश्यक स्थिति तर्क: 'func'

डेकोरेटर वर्ग

def decoratorfactory(*decorator_args, **decorator_kwargs):
    
    class Decorator(object):
        def __init__(self, func):
            self.func = func

        def __call__(self, *args, **kwargs):
            print('Inside the decorator with arguments {}'.format(decorator_args))
            return self.func(*args, **kwargs)
        
    return Decorator

@decoratorfactory(10)
def test():
    pass

test()

तर्क के साथ डेकोरेटर के अंदर (10)

एक डेकोरेटर के साथ सिंगलटन क्लास बनाएं

एक सिंगलटन एक ऐसा पैटर्न है जो एक वर्ग के तात्कालिकता को एक उदाहरण / वस्तु के लिए प्रतिबंधित करता है। डेकोरेटर का उपयोग करते हुए, हम क्लास को एक मौजूदा उदाहरण की कक्षा को वापस करने के लिए मजबूर करके एक सिंगलटन के रूप में एक वर्ग को परिभाषित कर सकते हैं या एक नया उदाहरण बना सकते हैं (यदि यह मौजूद नहीं है)।

def singleton(cls):    
    instance = [None]
    def wrapper(*args, **kwargs):
        if instance[0] is None:
            instance[0] = cls(*args, **kwargs)
        return instance[0]

    return wrapper

इस डेकोरेटर को किसी भी वर्ग घोषणा में जोड़ा जा सकता है और यह सुनिश्चित करेगा कि कक्षा के अधिकांश एक उदाहरण पर बनाया गया है। कोई भी बाद की कॉल पहले से मौजूद क्लास इंस्टेंस को लौटा देगी।

@singleton
class SomeSingletonClass:
    x = 2
    def __init__(self):
        print("Created!")

instance = SomeSingletonClass()  # prints: Created!
instance = SomeSingletonClass()  # doesn't print anything
print(instance.x)                # 2

instance.x = 3
print(SomeSingletonClass().x)    # 3

तो इससे कोई फर्क नहीं पड़ता कि आप अपने स्थानीय चर के माध्यम से वर्ग उदाहरण का उल्लेख करते हैं या क्या आप एक और "उदाहरण" बनाते हैं, आपको हमेशा एक ही वस्तु मिलती है।

एक समारोह के लिए एक डेकोरेटर का उपयोग करना

import time
def timer(func):
    def inner(*args, **kwargs):
        t1 = time.time()
        f = func(*args, **kwargs)
        t2 = time.time()
        print 'Runtime took {0} seconds'.format(t2-t1)
        return f
    return inner

@timer
def example_function():
    #do stuff


example_function()


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow