मापदंडों के साथ सज्जाकार?


401

मुझे डेकोरेटर द्वारा वेरिएबल 'Insurance_mode' के ट्रांसफर की समस्या है। मैं इसे निम्नलिखित डेकोरेटर स्टेटमेंट द्वारा करूँगा:

 @execute_complete_reservation(True)
 def test_booking_gta_object(self):
     self.test_select_gta_object()

लेकिन दुर्भाग्य से, यह कथन काम नहीं करता है। शायद इस समस्या को हल करने का बेहतर तरीका है।

def execute_complete_reservation(test_case,insurance_mode):
    def inner_function(self,*args,**kwargs):
        self.test_create_qsf_query()
        test_case(self,*args,**kwargs)
        self.test_select_room_option()
        if insurance_mode:
            self.test_accept_insurance_crosseling()
        else:
            self.test_decline_insurance_crosseling()
        self.test_configure_pax_details()
        self.test_configure_payer_details

    return inner_function

3
आपका उदाहरण वाक्यात्मक रूप से मान्य नहीं है। execute_complete_reservationदो पैरामीटर लेता है, लेकिन आप इसे एक पास कर रहे हैं। डेकोरेटर्स अन्य कार्यों के अंदर लपेटने के कार्यों के लिए सिंटैक्टिक शुगर हैं। पूर्ण दस्तावेज़ के लिए docs.python.org/reference/compound_stmts.html#function देखें ।
ब्रायन क्लैपर

जवाबों:


687

तर्क के साथ सज्जाकार के लिए वाक्य रचना पर कुछ भिन्न है - तर्क के साथ डेकोरेटर एक समारोह कि लौटना चाहिए एक समारोह ले और एक अन्य समारोह लौटने। तो यह वास्तव में एक सामान्य डेकोरेटर को वापस करना चाहिए। थोड़ा भ्रमित, है ना? मेरा कहने का तात्पर्य है:

def decorator_factory(argument):
    def decorator(function):
        def wrapper(*args, **kwargs):
            funny_stuff()
            something_with_argument(argument)
            result = function(*args, **kwargs)
            more_funny_stuff()
            return result
        return wrapper
    return decorator

यहां आप इस विषय पर अधिक पढ़ सकते हैं - कॉल करने योग्य वस्तुओं का उपयोग करके इसे लागू करना भी संभव है और यह भी वहां समझाया गया है।


56
मुझे आश्चर्य है कि जीवीआर ने 'फंक्शन' के बाद के डेकोरेटर तर्कों के रूप में मापदंडों को पारित करके इसे लागू क्यों नहीं किया। 'यो डॉग मैंने आपको बंदों की तरह सुना ...' वगैरह।
मिशेल मुलर

3
> कार्य पहले तर्क या अंतिम होगा? स्पष्ट रूप से पहले, चूंकि पैरामीटर चर लंबाई की एक पैरामीटर सूची है। > यह भी अजीब है कि आप फ़ंक्शन को परिभाषा में एक से अलग एक हस्ताक्षर के साथ "कॉल" करेंगे। जैसा कि आप बताते हैं, यह वास्तव में बहुत अच्छी तरह से फिट होगा - यह एक वर्ग विधि कैसे कहा जाता है के लिए बहुत अधिक अनुरूप है। इसे और अधिक स्पष्ट करने के लिए, आपके पास डेकोरेटर (self_func, param1, ...) सम्मेलन जैसा कुछ हो सकता है। लेकिन ध्यान दें: मैं यहाँ किसी भी बदलाव की वकालत नहीं कर रहा हूँ, अजगर इसके लिए सड़क से बहुत नीचे है और हम देख सकते हैं कि कैसे बदलावों को तोड़कर काम किया है ..
मिशेल मुलर

21
आप रैपर सजाने के लिए बहुत उपयोगी फंतासी भूल गए। :)
सॉकेटपेयर

10
जब आप फंक्शन को बुलाते हैं, तो आप भूल जाते हैं, इसका मतलब है return function(*args, **kwargs)
formiaczek

36
शायद स्पष्ट है, लेकिन सिर्फ मामले में: आपको इस डेकोरेटर का उपयोग करने की आवश्यकता है @decorator()और न केवल @decorator, भले ही आपके पास केवल वैकल्पिक तर्क हों।
पैट्रिक मेव्ज़ेक

324

संपादित करें : सज्जाकारों के मानसिक मॉडल की गहराई से समझ के लिए, इस भयानक पाइकॉन टॉक पर एक नज़र डालें । 30 मिनट के लायक।

तर्कों के साथ सज्जाकारों के बारे में सोचने का एक तरीका है

@decorator
def foo(*args, **kwargs):
    pass

में अनुवाद करता है

foo = decorator(foo)

तो अगर डेकोरेटर के पास तर्क थे,

@decorator_with_args(arg)
def foo(*args, **kwargs):
    pass

में अनुवाद करता है

foo = decorator_with_args(arg)(foo)

decorator_with_args एक फ़ंक्शन है जो एक कस्टम तर्क को स्वीकार करता है और जो वास्तविक डेकोरेटर को लौटाता है (जो सजाया गया फ़ंक्शन पर लागू होगा)।

मैं अपने डेकोरेटर्स को आसान बनाने के लिए पार्टिकल्स के साथ एक सरल ट्रिक का उपयोग करता हूं

from functools import partial

def _pseudo_decor(fun, argument):
    def ret_fun(*args, **kwargs):
        #do stuff here, for eg.
        print ("decorator arg is %s" % str(argument))
        return fun(*args, **kwargs)
    return ret_fun

real_decorator = partial(_pseudo_decor, argument=arg)

@real_decorator
def foo(*args, **kwargs):
    pass

अपडेट करें:

ऊपर, fooबन जाता हैreal_decorator(foo)

एक फ़ंक्शन को सजाने का एक प्रभाव यह है कि fooडेकोरेटर घोषणा पर नाम को ओवरराइड किया जाता है। fooजो कुछ भी लौटाया जाता है, उसके द्वारा "ओवरराइड" किया जाता है real_decorator। इस मामले में, एक नया फ़ंक्शन ऑब्जेक्ट।

सभी fooमेटाडेटा ओवरराइड है, विशेष रूप से डॉकस्ट्रिंग और फ़ंक्शन नाम।

>>> print(foo)
<function _pseudo_decor.<locals>.ret_fun at 0x10666a2f0>

functionalools.wraps हमें डॉकस्ट्रिंग और लौटे फ़ंक्शन को "लिफ्ट" करने के लिए एक सुविधाजनक विधि प्रदान करता है।

from functools import partial, wraps

def _pseudo_decor(fun, argument):
    # magic sauce to lift the name and doc of the function
    @wraps(fun)
    def ret_fun(*args, **kwargs):
        #do stuff here, for eg.
        print ("decorator arg is %s" % str(argument))
        return fun(*args, **kwargs)
    return ret_fun

real_decorator = partial(_pseudo_decor, argument=arg)

@real_decorator
def bar(*args, **kwargs):
    pass

>>> print(bar)
<function __main__.bar(*args, **kwargs)>

4
आपके उत्तर ने डेकोरेटर की अंतर्निहित
रूढ़िवादिता को

क्या आप जोड़ सकते हैं @functools.wraps?
Mr_and_Mrs_D

1
@Mr_and_Mrs_D, मैंने एक उदाहरण के साथ पोस्ट अपडेट किया है functool.wraps। इसे उदाहरण में जोड़ना पाठकों को और भ्रमित कर सकता है।
srj

7
argयहाँ क्या है !?
डिस्प्लेनेम

1
आप तर्क को कैसे पारित करेंगे के तर्क को पारित किया barहै real_decorator?
चांग झाओ

85

मैं एक आइडिया दिखाना चाहता हूं जो IMHO काफी एलिगेंट है। T.dubrownik द्वारा प्रस्तावित समाधान एक पैटर्न दिखाता है जो हमेशा समान होता है: आपको तीन-स्तरित आवरण की आवश्यकता होती है, भले ही डेकोरेटर क्या करता है।

तो मैंने सोचा कि यह एक मेटा-डेकोरेटर के लिए एक नौकरी है, अर्थात् सज्जाकारों के लिए एक डेकोरेटर है। डेकोरेटर एक फ़ंक्शन है, यह वास्तव में तर्कों के साथ एक नियमित डेकोरेटर के रूप में काम करता है:

def parametrized(dec):
    def layer(*args, **kwargs):
        def repl(f):
            return dec(f, *args, **kwargs)
        return repl
    return layer

मापदंडों को जोड़ने के लिए यह एक नियमित डेकोरेटर पर लागू किया जा सकता है। उदाहरण के लिए, मान लें कि हमारे पास डेकोरेटर है जो एक फ़ंक्शन के परिणाम को दोगुना करता है:

def double(f):
    def aux(*xs, **kws):
        return 2 * f(*xs, **kws)
    return aux

@double
def function(a):
    return 10 + a

print function(3)    # Prints 26, namely 2 * (10 + 3)

साथ @parametrizedहम एक सामान्य निर्माण कर सकते हैं @multiplyडेकोरेटर एक पैरामीटर होने

@parametrized
def multiply(f, n):
    def aux(*xs, **kws):
        return n * f(*xs, **kws)
    return aux

@multiply(2)
def function(a):
    return 10 + a

print function(3)    # Prints 26

@multiply(3)
def function_again(a):
    return 10 + a

print function(3)          # Keeps printing 26
print function_again(3)    # Prints 39, namely 3 * (10 + 3)

परंपरागत रूप से एक पैरामीरिज्ड डेकोरेटर का पहला पैरामीटर फ़ंक्शन है, जबकि शेष तर्क पैरामीरीज़ेड डेकोरेटर के पैरामीटर के अनुरूप होंगे।

एक दिलचस्प उपयोग उदाहरण एक प्रकार का सुरक्षित मुखर सज्जाकार हो सकता है:

import itertools as it

@parametrized
def types(f, *types):
    def rep(*args):
        for a, t, n in zip(args, types, it.count()):
            if type(a) is not t:
                raise TypeError('Value %d has not type %s. %s instead' %
                    (n, t, type(a))
                )
        return f(*args)
    return rep

@types(str, int)  # arg1 is str, arg2 is int
def string_multiply(text, times):
    return text * times

print(string_multiply('hello', 3))    # Prints hellohellohello
print(string_multiply(3, 3))          # Fails miserably with TypeError

एक अंतिम नोट: यहां मैं functools.wrapsआवरण कार्यों के लिए उपयोग नहीं कर रहा हूं , लेकिन मैं इसे हर समय उपयोग करने की सलाह दूंगा।


3
यह बिल्कुल उपयोग नहीं किया, लेकिन मुझे अवधारणा के आसपास अपना सिर लाने में मदद मिली :) धन्यवाद!
माउकैट्रॉन

मैंने यह कोशिश की और कुछ मुद्दे थे
जेफ

@ जेफ़ आप हमारे साथ साझा कर सकते हैं कि आपके पास किस तरह के मुद्दे हैं?
दकाव

मैंने इसे अपने प्रश्न पर जोड़ा था, और मैंने इसका पता लगा लिया ... मुझे @wrapsअपने विशेष मामले के लिए कॉल करने की आवश्यकता थी ।
जेफ

4
ओह बॉय, मैं इस पर एक पूरा दिन खो दिया। शुक्र है, मैं इस उत्तर के आसपास आया (जो संयोग से पूरे इंटरनेट पर बनाया गया सर्वश्रेष्ठ उत्तर हो सकता है)। वे भी आपकी @parametrizedचाल का उपयोग करते हैं । मेरे पास जो समस्या थी मैं भूल गया था कि @वाक्यविन्यास वास्तविक कॉल के बराबर है (किसी तरह मुझे पता था कि और मुझे नहीं पता था कि एक ही समय में आप मेरे प्रश्न से इकट्ठा कर सकते हैं)। इसलिए यदि आप @सिंटैक्स को सांसारिक कॉल्स में अनुवाद करना चाहते हैं , तो यह जांचने के लिए कि यह कैसे काम करता है, आप इसे पहले अस्थायी रूप से टिप्पणी करते हैं या आप इसे दो बार कॉल करते हैं और mumbojumbo परिणाम प्राप्त कर रहे हैं
z33k

79

यहाँ t.dubrownik के उत्तर का थोड़ा संशोधित संस्करण है । क्यों?

  1. एक सामान्य टेम्पलेट के रूप में, आपको मूल फ़ंक्शन से वापसी मान वापस करना चाहिए।
  2. इससे फ़ंक्शन का नाम बदल जाता है, जो अन्य सज्जाकार / कोड को प्रभावित कर सकता है।

तो उपयोग करें @functools.wraps():

from functools import wraps

def decorator(argument):
    def real_decorator(function):
        @wraps(function)
        def wrapper(*args, **kwargs):
            funny_stuff()
            something_with_argument(argument)
            retval = function(*args, **kwargs)
            more_funny_stuff()
            return retval
        return wrapper
    return real_decorator

37

मुझे लगता है कि आपकी समस्या आपके डेकोरेटर के लिए तर्क दे रही है। यह थोड़ा मुश्किल है और सीधा नहीं है।

यह कैसे करना है इसका एक उदाहरण इस प्रकार है:

class MyDec(object):
    def __init__(self,flag):
        self.flag = flag
    def __call__(self, original_func):
        decorator_self = self
        def wrappee( *args, **kwargs):
            print 'in decorator before wrapee with flag ',decorator_self.flag
            original_func(*args,**kwargs)
            print 'in decorator after wrapee with flag ',decorator_self.flag
        return wrappee

@MyDec('foo de fa fa')
def bar(a,b,c):
    print 'in bar',a,b,c

bar('x','y','z')

प्रिंटों:

in decorator before wrapee with flag  foo de fa fa
in bar x y z
in decorator after wrapee with flag  foo de fa fa

अधिक विवरण के लिए ब्रूस एकेल का लेख देखें।


20
डेकोरेटर वर्गों से सावधान रहें। वे तब तक तरीकों पर काम नहीं करते हैं जब तक कि आप मैन्युअल रूप से इंस्टीट्यूशन डिस्क्रिप्टर के तर्क को पुष्ट न करें।

9
डेलान, देखभाल करने के लिए विस्तृत? मुझे केवल एक बार इस पैटर्न का उपयोग करना पड़ा है, इसलिए मैंने अभी तक किसी भी नुकसान को नहीं मारा है।
रॉस रोजर्स

2
@RossRogers मेरा अनुमान है कि @delnan उन चीजों का जिक्र कर रहा है, __name__जिनमें सज्जाकार वर्ग का उदाहरण नहीं होगा?

9
@jamesc वह भी, हालांकि इसे हल करना अपेक्षाकृत आसान है। मैं जिस विशिष्ट मामले का जिक्र कर रहा था class Foo: @MyDec(...) def method(self, ...): blah, वह काम नहीं करता क्योंकि Foo().methodएक बाध्य पद्धति नहीं होगी और selfस्वचालित रूप से पारित नहीं होगी । यह भी MyDecएक डिस्क्रिप्टर बनाकर और बाध्य तरीकों से तय किया जा सकता है __get__, लेकिन यह अधिक शामिल है और बहुत कम स्पष्ट है। अंत में, डेकोरेटर कक्षाएं उतनी सुविधाजनक नहीं हैं जितनी वे लगती हैं।

2
@delnan मैं यह देखना चाहता हूं कि इस चेतावनी को अधिक प्रमुखता से दिखाया गया है। मैं इसे मार रहा हूं और एक समाधान को देखने में दिलचस्पी रखता हूं जो काम करता है (अधिक स्पष्ट रूप से इसमें शामिल नहीं है, हालांकि यह हो सकता है)।
हापसंतरण

12
def decorator(argument):
    def real_decorator(function):
        def wrapper(*args):
            for arg in args:
                assert type(arg)==int,f'{arg} is not an interger'
            result = function(*args)
            result = result*argument
            return result
        return wrapper
    return real_decorator

डेकोरेटर का उपयोग

@decorator(2)
def adder(*args):
    sum=0
    for i in args:
        sum+=i
    return sum

फिर

adder(2,3)

पैदा करता है

10

परंतु

adder('hi',3)

पैदा करता है

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-143-242a8feb1cc4> in <module>
----> 1 adder('hi',3)

<ipython-input-140-d3420c248ebd> in wrapper(*args)
      3         def wrapper(*args):
      4             for arg in args:
----> 5                 assert type(arg)==int,f'{arg} is not an interger'
      6             result = function(*args)
      7             result = result*argument

AssertionError: hi is not an interger

8

यह एक फ़ंक्शन डेकोरेटर के लिए एक टेम्प्लेट है जिसे आवश्यकता नहीं है ()यदि कोई पैरामीटर नहीं दिया जाना है:

import functools


def decorator(x_or_func=None, *decorator_args, **decorator_kws):
    def _decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kws):
            if 'x_or_func' not in locals() \
                    or callable(x_or_func) \
                    or x_or_func is None:
                x = ...  # <-- default `x` value
            else:
                x = x_or_func
            return func(*args, **kws)

        return wrapper

    return _decorator(x_or_func) if callable(x_or_func) else _decorator

इसका एक उदाहरण नीचे दिया गया है:

def multiplying(factor_or_func=None):
    def _decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            if 'factor_or_func' not in locals() \
                    or callable(factor_or_func) \
                    or factor_or_func is None:
                factor = 1
            else:
                factor = factor_or_func
            return factor * func(*args, **kwargs)
        return wrapper
    return _decorator(factor_or_func) if callable(factor_or_func) else _decorator


@multiplying
def summing(x): return sum(x)

print(summing(range(10)))
# 45


@multiplying()
def summing(x): return sum(x)

print(summing(range(10)))
# 45


@multiplying(10)
def summing(x): return sum(x)

print(summing(range(10)))
# 450

यह भी ध्यान दें कि factor_or_func(या किसी अन्य पैरामीटर) कभी नहीं पुन: असाइन हो जाता है चाहिए में wrapper()
नोरोक 2

आपको जांच करने की आवश्यकता क्यों है locals()?
शीतल शाह

@ शीतलशाह उस मामले को कवर करता है, जहां डेकोरेटर का उपयोग किए बिना किया जाता है ()
नोरोक 2

4

मेरे उदाहरण में, मैंने एक नया डेकोरेटर फ़ंक्शन बनाने के लिए एक-लाइन लैंबडा के माध्यम से इसे हल करने का फैसला किया:

def finished_message(function, message="Finished!"):

    def wrapper(*args, **kwargs):
        output = function(*args,**kwargs)
        print(message)
        return output

    return wrapper

@finished_message
def func():
    pass

my_finished_message = lambda f: finished_message(f, "All Done!")

@my_finished_message
def my_func():
    pass

if __name__ == '__main__':
    func()
    my_func()

निष्पादित होने पर, यह प्रिंट करता है:

Finished!
All Done!

शायद अन्य समाधानों की तरह एक्स्टेंसिबल नहीं है, लेकिन मेरे लिए काम किया।


यह काम। यद्यपि हां, इससे डेकोरेटर के लिए मूल्य निर्धारित करना मुश्किल हो जाता है।
अरिंदम रॉयचौधरी

3

एक डेकोरेटर लिखना जो पैरामीटर के साथ और बिना काम करता है, एक चुनौती है क्योंकि पायथन को इन दो मामलों में पूरी तरह से अलग व्यवहार की उम्मीद है! कई उत्तरों ने इसके आस-पास काम करने की कोशिश की है और नीचे दिए गए उत्तर में @ norok2 से सुधार है। विशेष रूप से, यह भिन्नता उपयोग को समाप्त करती हैlocals()

@ Norok2 द्वारा दिए गए उदाहरण के समान:

import functools

def multiplying(f_py=None, factor=1):
    assert callable(f_py) or f_py is None
    def _decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            return factor * func(*args, **kwargs)
        return wrapper
    return _decorator(f_py) if callable(f_py) else _decorator


@multiplying
def summing(x): return sum(x)

print(summing(range(10)))
# 45


@multiplying()
def summing(x): return sum(x)

print(summing(range(10)))
# 45


@multiplying(factor=10)
def summing(x): return sum(x)

print(summing(range(10)))
# 450

इस कोड के साथ खेलते हैं

पकड़ यह है कि उपयोगकर्ता को प्रमुख मापदंडों के बजाय मापदंडों के प्रमुख जोड़े, मूल्य जोड़े की आपूर्ति करनी चाहिए और पहला पैरामीटर आरक्षित है।


2

यह सर्वविदित है कि निम्नलिखित दो टुकड़े कोड लगभग बराबर हैं:

@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

1

अनुकूलित डेकोरेटर फ़ंक्शन उत्पन्न करने के लिए इस "डेकोरेटाइज़ फ़ंक्शन" को परिभाषित करें:

def decoratorize(FUN, **kw):
    def foo(*args, **kws):
        return FUN(*args, **kws, **kw)
    return foo

इसे इस तरह से उपयोग करें:

    @decoratorize(FUN, arg1 = , arg2 = , ...)
    def bar(...):
        ...

1

ऊपर महान जवाब। यह भी दिखाता है @wraps, जो मूल फ़ंक्शन से डॉक्टर स्ट्रिंग और फ़ंक्शन नाम लेता है और इसे नए लिपटे संस्करण पर लागू होता है:

from functools import wraps

def decorator_func_with_args(arg1, arg2):
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            print("Before orginal function with decorator args:", arg1, arg2)
            result = f(*args, **kwargs)
            print("Ran after the orginal function")
            return result
        return wrapper
    return decorator

@decorator_func_with_args("foo", "bar")
def hello(name):
    """A function which prints a greeting to the name provided.
    """
    print('hello ', name)
    return 42

print("Starting script..")
x = hello('Bob')
print("The value of x is:", x)
print("The wrapped functions docstring is:", hello.__doc__)
print("The wrapped functions name is:", hello.__name__)

प्रिंटों:

Starting script..
Before orginal function with decorator args: foo bar
hello  Bob
Ran after the orginal function
The value of x is: 42
The wrapped functions docstring is: A function which prints a greeting to the name provided.
The wrapped functions name is: hello

0

यदि फ़ंक्शन और डेकोरेटर दोनों को तर्क देना है तो आप नीचे दिए गए दृष्टिकोण का पालन कर सकते हैं।

उदाहरण के लिए एक डेकोरेटर है जिसका नाम है decorator1 तर्क है

@decorator1(5)
def func1(arg1, arg2):
    print (arg1, arg2)

func1(1, 2)

अब अगर द decorator1 तर्क को गतिशील होना है, या फ़ंक्शन को कॉल करते समय पारित किया गया है,

def func1(arg1, arg2):
    print (arg1, arg2)


a = 1
b = 2
seconds = 10

decorator1(seconds)(func1)(a, b)

उपरोक्त कोड में

  • seconds के लिए तर्क है decorator1
  • a, b के तर्क हैं func1
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.