Decorators with parameters?

Multi tool use
Multi tool use












292















I have a problem with the transfer of variable 'insurance_mode' by the decorator. I would do it by the following decorator statement:



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


but unfortunately, this statement does not work. Perhaps maybe there is better way to solve this problem.



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









share|improve this question




















  • 2





    Your example is not syntactically valid. execute_complete_reservation takes two parameters, but you're passing it one. Decorators are just syntactic sugar for wrapping functions inside other functions. See docs.python.org/reference/compound_stmts.html#function for complete documentation.

    – Brian Clapper
    May 8 '11 at 17:50


















292















I have a problem with the transfer of variable 'insurance_mode' by the decorator. I would do it by the following decorator statement:



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


but unfortunately, this statement does not work. Perhaps maybe there is better way to solve this problem.



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









share|improve this question




















  • 2





    Your example is not syntactically valid. execute_complete_reservation takes two parameters, but you're passing it one. Decorators are just syntactic sugar for wrapping functions inside other functions. See docs.python.org/reference/compound_stmts.html#function for complete documentation.

    – Brian Clapper
    May 8 '11 at 17:50
















292












292








292


122






I have a problem with the transfer of variable 'insurance_mode' by the decorator. I would do it by the following decorator statement:



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


but unfortunately, this statement does not work. Perhaps maybe there is better way to solve this problem.



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









share|improve this question
















I have a problem with the transfer of variable 'insurance_mode' by the decorator. I would do it by the following decorator statement:



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


but unfortunately, this statement does not work. Perhaps maybe there is better way to solve this problem.



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






python decorator






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jun 6 '17 at 17:45









martineau

66.9k989180




66.9k989180










asked May 8 '11 at 17:40









falek.marcinfalek.marcin

2,13872131




2,13872131








  • 2





    Your example is not syntactically valid. execute_complete_reservation takes two parameters, but you're passing it one. Decorators are just syntactic sugar for wrapping functions inside other functions. See docs.python.org/reference/compound_stmts.html#function for complete documentation.

    – Brian Clapper
    May 8 '11 at 17:50
















  • 2





    Your example is not syntactically valid. execute_complete_reservation takes two parameters, but you're passing it one. Decorators are just syntactic sugar for wrapping functions inside other functions. See docs.python.org/reference/compound_stmts.html#function for complete documentation.

    – Brian Clapper
    May 8 '11 at 17:50










2




2





Your example is not syntactically valid. execute_complete_reservation takes two parameters, but you're passing it one. Decorators are just syntactic sugar for wrapping functions inside other functions. See docs.python.org/reference/compound_stmts.html#function for complete documentation.

– Brian Clapper
May 8 '11 at 17:50







Your example is not syntactically valid. execute_complete_reservation takes two parameters, but you're passing it one. Decorators are just syntactic sugar for wrapping functions inside other functions. See docs.python.org/reference/compound_stmts.html#function for complete documentation.

– Brian Clapper
May 8 '11 at 17:50














8 Answers
8






active

oldest

votes


















518














You mean def test_booking_gta_object, right? Anyway, the syntax for decorators with arguments is a bit different - the decorator with arguments should return a function that will take a function and return another function. So it should really return a normal decorator. A bit confusing, right? What I mean is:



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


Here you can read more on the subject - it's also possible to implement this using callable objects and that is also explained there.






share|improve this answer





















  • 2





    I just did this with lambdas all over the place. (read: Python is awesome!) :)

    – Alois Mahdal
    Jun 6 '13 at 15:36






  • 35





    I wonder why GVR didn't implement it by passing in the parameters as subsequent decorator arguments after 'function'. 'Yo dawg I heard you like closures...' etcetera.

    – Michel Müller
    Apr 8 '14 at 16:22






  • 14





    you forgot VERY USEFUL functools.wraps for decorating wrapper :)

    – socketpair
    Aug 13 '15 at 21:19








  • 10





    You forgot about return when calling function, i.e. return function(*args, **kwargs)

    – formiaczek
    Dec 1 '15 at 17:09








  • 20





    Maybe obvious, but just in case: you need to use this decorator as @decorator() and not just @decorator, even if you have only optional arguments.

    – Patrick Mevzek
    Dec 4 '17 at 20:25



















226














One way of thinking about decorators with arguments is



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


translates to



foo = decorator(foo)


So if the decorator had arguments,



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


translates to



foo = decorator_with_args(arg)(foo)


decorator_with_args is a function which accepts a custom argument and which returns the actual decorator (that will be applied to the decorated function).



I use a simple trick with partials to make my decorators easy



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


Update:



Above, foo becomes real_decorator(foo)



One effect of decorating a function is that the name foo is overridden upon decorator declaration. foo is "overridden" by whatever is returned by real_decorator. In this case, a new function object.



All of foo's metadata is overridden, notably docstring and function name.



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


functools.wraps gives us a convenient method to "lift" the docstring and name to the returned function.



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)>





share|improve this answer





















  • 1





    Your answer perfectly explained the inherent orthogonality of the decorator, thank you

    – zsf222
    Dec 9 '17 at 15:58






  • 1





    life saving answer!.

    – saiteja pakalapati
    Jul 12 '18 at 11:51











  • Could you add @functools.wraps?

    – Mr_and_Mrs_D
    Aug 26 '18 at 20:48






  • 1





    @Mr_and_Mrs_D , I've updated the post with an example with functool.wraps. Adding it in the example may confuse readers further.

    – srj
    Aug 28 '18 at 2:31






  • 2





    What is arg here!?

    – displayname
    Sep 25 '18 at 10:22



















66














I'd like to show an idea which is IMHO quite elegant. The solution proposed by t.dubrownik shows a pattern which is always the same: you need the three-layered wrapper regardless of what the decorator does.



So I thought this is a job for a meta-decorator, that is, a decorator for decorators. As a decorator is a function, it actually works as a regular decorator with arguments:



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


This can be applied to a regular decorator in order to add parameters. So for instance, say we have the decorator which doubles the result of a function:



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)


With @parametrized we can build a generic @multiply decorator having a parameter



@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)


Conventionally the first parameter of a parametrized decorator is the function, while the remaining arguments will correspond to the parameter of the parametrized decorator.



An interesting usage example could be a type-safe assertive decorator:



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


A final note: here I'm not using functools.wraps for the wrapper functions, but I would recommend using it all the times.






share|improve this answer


























  • Didn't use this exactly, but helped me get my head around the concept :) Thanks!

    – mouckatron
    Oct 10 '17 at 22:04











  • I tried this and had some issues.

    – Jeff
    Oct 14 '17 at 14:53













  • @Jeff could you share with us the kind of issues you had?

    – Dacav
    Oct 14 '17 at 16:49











  • I had it linked on my question, and I did figure it out... I needed to call @wraps in mine for my particular case.

    – Jeff
    Oct 14 '17 at 19:33






  • 3





    Oh boy, I lost a whole day on this. Thankfully, I came around this answer (which incidentally could be the best answer ever created on the whole internet). They too use your @parametrized trick. The problem I had was I forgot the @ syntax equals actual calls (somehow I knew that and didn't know that at the same time as you can gather from my question). So if you want to translate @ syntax into mundane calls to check how it works, you better comment it out temporarily first or you'd end up calling it twice and getting mumbojumbo results

    – z33k
    Mar 13 '18 at 14:50





















51














Here is a slightly modified version of t.dubrownik's answer. Why?




  1. As a general template, you should return the return value from the original function.

  2. This changes the name of the function, which could affect other decorators / code.


So use @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





share|improve this answer

































    35














    I presume your problem is passing arguments to your decorator. This is a little tricky and not straightforward.



    Here's an example of how to do this:



    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')


    Prints:



    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


    See Bruce Eckel's article for more details.






    share|improve this answer





















    • 19





      Beware of decorator classes. They don't work on methods unless you manually reinvent the logic of instancemethod descriptors.

      – user395760
      May 8 '11 at 18:01






    • 9





      delnan, care to elaborate? I've only had to use this pattern once, so I haven't hit any of the pitfalls yet.

      – Ross Rogers
      May 8 '11 at 18:04








    • 2





      @RossRogers My guess is that @delnan is referring to things like __name__ which an instance of the decorator class won't have?

      – jamesc
      Jan 13 '14 at 17:18






    • 9





      @jamesc That too, though that's relatively easy to solve. The specific case I was referring to was class Foo: @MyDec(...) def method(self, ...): blah which does not work because Foo().method won't be a bound method and won't pass self automatically. This too can be fixed, by making MyDec a descriptor and creating bound methods in __get__, but it's more involved and much less obvious. In the end, decorator classes are not as convenient as they seem.

      – user395760
      Jan 13 '14 at 21:49








    • 2





      @delnan I'd like to see this caveat featured more prominently. I'm hitting it and am interested in seeing a solution that DOES work (more involved an less obvious though it may be).

      – HaPsantran
      Mar 13 '16 at 6:42



















    1














    In my instance, I decided to solve this via a one-line lambda to create a new decorator function:



    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()


    When executed, this prints:



    Finished!
    All Done!


    Perhaps not as extensible as other solutions, but worked for me.






    share|improve this answer
























    • This works. Although yes, this makes it hard to set the value to the decorator.

      – Arindam Roychowdhury
      Jan 11 at 11:28



















    0














    define this "decoratorize function" to generate customized decorator function:



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


    use it this way:



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





    share|improve this answer































      0














      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


      Usage of the decorator



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


      Then the



      adder(2,3)


      produces



      10


      but



      adder('hi',3)


      produces



      ---------------------------------------------------------------------------
      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





      share|improve this answer























        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f5929107%2fdecorators-with-parameters%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        8 Answers
        8






        active

        oldest

        votes








        8 Answers
        8






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        518














        You mean def test_booking_gta_object, right? Anyway, the syntax for decorators with arguments is a bit different - the decorator with arguments should return a function that will take a function and return another function. So it should really return a normal decorator. A bit confusing, right? What I mean is:



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


        Here you can read more on the subject - it's also possible to implement this using callable objects and that is also explained there.






        share|improve this answer





















        • 2





          I just did this with lambdas all over the place. (read: Python is awesome!) :)

          – Alois Mahdal
          Jun 6 '13 at 15:36






        • 35





          I wonder why GVR didn't implement it by passing in the parameters as subsequent decorator arguments after 'function'. 'Yo dawg I heard you like closures...' etcetera.

          – Michel Müller
          Apr 8 '14 at 16:22






        • 14





          you forgot VERY USEFUL functools.wraps for decorating wrapper :)

          – socketpair
          Aug 13 '15 at 21:19








        • 10





          You forgot about return when calling function, i.e. return function(*args, **kwargs)

          – formiaczek
          Dec 1 '15 at 17:09








        • 20





          Maybe obvious, but just in case: you need to use this decorator as @decorator() and not just @decorator, even if you have only optional arguments.

          – Patrick Mevzek
          Dec 4 '17 at 20:25
















        518














        You mean def test_booking_gta_object, right? Anyway, the syntax for decorators with arguments is a bit different - the decorator with arguments should return a function that will take a function and return another function. So it should really return a normal decorator. A bit confusing, right? What I mean is:



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


        Here you can read more on the subject - it's also possible to implement this using callable objects and that is also explained there.






        share|improve this answer





















        • 2





          I just did this with lambdas all over the place. (read: Python is awesome!) :)

          – Alois Mahdal
          Jun 6 '13 at 15:36






        • 35





          I wonder why GVR didn't implement it by passing in the parameters as subsequent decorator arguments after 'function'. 'Yo dawg I heard you like closures...' etcetera.

          – Michel Müller
          Apr 8 '14 at 16:22






        • 14





          you forgot VERY USEFUL functools.wraps for decorating wrapper :)

          – socketpair
          Aug 13 '15 at 21:19








        • 10





          You forgot about return when calling function, i.e. return function(*args, **kwargs)

          – formiaczek
          Dec 1 '15 at 17:09








        • 20





          Maybe obvious, but just in case: you need to use this decorator as @decorator() and not just @decorator, even if you have only optional arguments.

          – Patrick Mevzek
          Dec 4 '17 at 20:25














        518












        518








        518







        You mean def test_booking_gta_object, right? Anyway, the syntax for decorators with arguments is a bit different - the decorator with arguments should return a function that will take a function and return another function. So it should really return a normal decorator. A bit confusing, right? What I mean is:



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


        Here you can read more on the subject - it's also possible to implement this using callable objects and that is also explained there.






        share|improve this answer















        You mean def test_booking_gta_object, right? Anyway, the syntax for decorators with arguments is a bit different - the decorator with arguments should return a function that will take a function and return another function. So it should really return a normal decorator. A bit confusing, right? What I mean is:



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


        Here you can read more on the subject - it's also possible to implement this using callable objects and that is also explained there.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Apr 21 '18 at 18:38









        Zen

        1,02331533




        1,02331533










        answered May 8 '11 at 17:54









        t.dubrownikt.dubrownik

        5,9761115




        5,9761115








        • 2





          I just did this with lambdas all over the place. (read: Python is awesome!) :)

          – Alois Mahdal
          Jun 6 '13 at 15:36






        • 35





          I wonder why GVR didn't implement it by passing in the parameters as subsequent decorator arguments after 'function'. 'Yo dawg I heard you like closures...' etcetera.

          – Michel Müller
          Apr 8 '14 at 16:22






        • 14





          you forgot VERY USEFUL functools.wraps for decorating wrapper :)

          – socketpair
          Aug 13 '15 at 21:19








        • 10





          You forgot about return when calling function, i.e. return function(*args, **kwargs)

          – formiaczek
          Dec 1 '15 at 17:09








        • 20





          Maybe obvious, but just in case: you need to use this decorator as @decorator() and not just @decorator, even if you have only optional arguments.

          – Patrick Mevzek
          Dec 4 '17 at 20:25














        • 2





          I just did this with lambdas all over the place. (read: Python is awesome!) :)

          – Alois Mahdal
          Jun 6 '13 at 15:36






        • 35





          I wonder why GVR didn't implement it by passing in the parameters as subsequent decorator arguments after 'function'. 'Yo dawg I heard you like closures...' etcetera.

          – Michel Müller
          Apr 8 '14 at 16:22






        • 14





          you forgot VERY USEFUL functools.wraps for decorating wrapper :)

          – socketpair
          Aug 13 '15 at 21:19








        • 10





          You forgot about return when calling function, i.e. return function(*args, **kwargs)

          – formiaczek
          Dec 1 '15 at 17:09








        • 20





          Maybe obvious, but just in case: you need to use this decorator as @decorator() and not just @decorator, even if you have only optional arguments.

          – Patrick Mevzek
          Dec 4 '17 at 20:25








        2




        2





        I just did this with lambdas all over the place. (read: Python is awesome!) :)

        – Alois Mahdal
        Jun 6 '13 at 15:36





        I just did this with lambdas all over the place. (read: Python is awesome!) :)

        – Alois Mahdal
        Jun 6 '13 at 15:36




        35




        35





        I wonder why GVR didn't implement it by passing in the parameters as subsequent decorator arguments after 'function'. 'Yo dawg I heard you like closures...' etcetera.

        – Michel Müller
        Apr 8 '14 at 16:22





        I wonder why GVR didn't implement it by passing in the parameters as subsequent decorator arguments after 'function'. 'Yo dawg I heard you like closures...' etcetera.

        – Michel Müller
        Apr 8 '14 at 16:22




        14




        14





        you forgot VERY USEFUL functools.wraps for decorating wrapper :)

        – socketpair
        Aug 13 '15 at 21:19







        you forgot VERY USEFUL functools.wraps for decorating wrapper :)

        – socketpair
        Aug 13 '15 at 21:19






        10




        10





        You forgot about return when calling function, i.e. return function(*args, **kwargs)

        – formiaczek
        Dec 1 '15 at 17:09







        You forgot about return when calling function, i.e. return function(*args, **kwargs)

        – formiaczek
        Dec 1 '15 at 17:09






        20




        20





        Maybe obvious, but just in case: you need to use this decorator as @decorator() and not just @decorator, even if you have only optional arguments.

        – Patrick Mevzek
        Dec 4 '17 at 20:25





        Maybe obvious, but just in case: you need to use this decorator as @decorator() and not just @decorator, even if you have only optional arguments.

        – Patrick Mevzek
        Dec 4 '17 at 20:25













        226














        One way of thinking about decorators with arguments is



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


        translates to



        foo = decorator(foo)


        So if the decorator had arguments,



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


        translates to



        foo = decorator_with_args(arg)(foo)


        decorator_with_args is a function which accepts a custom argument and which returns the actual decorator (that will be applied to the decorated function).



        I use a simple trick with partials to make my decorators easy



        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


        Update:



        Above, foo becomes real_decorator(foo)



        One effect of decorating a function is that the name foo is overridden upon decorator declaration. foo is "overridden" by whatever is returned by real_decorator. In this case, a new function object.



        All of foo's metadata is overridden, notably docstring and function name.



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


        functools.wraps gives us a convenient method to "lift" the docstring and name to the returned function.



        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)>





        share|improve this answer





















        • 1





          Your answer perfectly explained the inherent orthogonality of the decorator, thank you

          – zsf222
          Dec 9 '17 at 15:58






        • 1





          life saving answer!.

          – saiteja pakalapati
          Jul 12 '18 at 11:51











        • Could you add @functools.wraps?

          – Mr_and_Mrs_D
          Aug 26 '18 at 20:48






        • 1





          @Mr_and_Mrs_D , I've updated the post with an example with functool.wraps. Adding it in the example may confuse readers further.

          – srj
          Aug 28 '18 at 2:31






        • 2





          What is arg here!?

          – displayname
          Sep 25 '18 at 10:22
















        226














        One way of thinking about decorators with arguments is



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


        translates to



        foo = decorator(foo)


        So if the decorator had arguments,



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


        translates to



        foo = decorator_with_args(arg)(foo)


        decorator_with_args is a function which accepts a custom argument and which returns the actual decorator (that will be applied to the decorated function).



        I use a simple trick with partials to make my decorators easy



        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


        Update:



        Above, foo becomes real_decorator(foo)



        One effect of decorating a function is that the name foo is overridden upon decorator declaration. foo is "overridden" by whatever is returned by real_decorator. In this case, a new function object.



        All of foo's metadata is overridden, notably docstring and function name.



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


        functools.wraps gives us a convenient method to "lift" the docstring and name to the returned function.



        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)>





        share|improve this answer





















        • 1





          Your answer perfectly explained the inherent orthogonality of the decorator, thank you

          – zsf222
          Dec 9 '17 at 15:58






        • 1





          life saving answer!.

          – saiteja pakalapati
          Jul 12 '18 at 11:51











        • Could you add @functools.wraps?

          – Mr_and_Mrs_D
          Aug 26 '18 at 20:48






        • 1





          @Mr_and_Mrs_D , I've updated the post with an example with functool.wraps. Adding it in the example may confuse readers further.

          – srj
          Aug 28 '18 at 2:31






        • 2





          What is arg here!?

          – displayname
          Sep 25 '18 at 10:22














        226












        226








        226







        One way of thinking about decorators with arguments is



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


        translates to



        foo = decorator(foo)


        So if the decorator had arguments,



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


        translates to



        foo = decorator_with_args(arg)(foo)


        decorator_with_args is a function which accepts a custom argument and which returns the actual decorator (that will be applied to the decorated function).



        I use a simple trick with partials to make my decorators easy



        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


        Update:



        Above, foo becomes real_decorator(foo)



        One effect of decorating a function is that the name foo is overridden upon decorator declaration. foo is "overridden" by whatever is returned by real_decorator. In this case, a new function object.



        All of foo's metadata is overridden, notably docstring and function name.



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


        functools.wraps gives us a convenient method to "lift" the docstring and name to the returned function.



        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)>





        share|improve this answer















        One way of thinking about decorators with arguments is



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


        translates to



        foo = decorator(foo)


        So if the decorator had arguments,



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


        translates to



        foo = decorator_with_args(arg)(foo)


        decorator_with_args is a function which accepts a custom argument and which returns the actual decorator (that will be applied to the decorated function).



        I use a simple trick with partials to make my decorators easy



        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


        Update:



        Above, foo becomes real_decorator(foo)



        One effect of decorating a function is that the name foo is overridden upon decorator declaration. foo is "overridden" by whatever is returned by real_decorator. In this case, a new function object.



        All of foo's metadata is overridden, notably docstring and function name.



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


        functools.wraps gives us a convenient method to "lift" the docstring and name to the returned function.



        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)>






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Aug 28 '18 at 2:31

























        answered Sep 13 '14 at 19:52









        srjsrj

        5,15421424




        5,15421424








        • 1





          Your answer perfectly explained the inherent orthogonality of the decorator, thank you

          – zsf222
          Dec 9 '17 at 15:58






        • 1





          life saving answer!.

          – saiteja pakalapati
          Jul 12 '18 at 11:51











        • Could you add @functools.wraps?

          – Mr_and_Mrs_D
          Aug 26 '18 at 20:48






        • 1





          @Mr_and_Mrs_D , I've updated the post with an example with functool.wraps. Adding it in the example may confuse readers further.

          – srj
          Aug 28 '18 at 2:31






        • 2





          What is arg here!?

          – displayname
          Sep 25 '18 at 10:22














        • 1





          Your answer perfectly explained the inherent orthogonality of the decorator, thank you

          – zsf222
          Dec 9 '17 at 15:58






        • 1





          life saving answer!.

          – saiteja pakalapati
          Jul 12 '18 at 11:51











        • Could you add @functools.wraps?

          – Mr_and_Mrs_D
          Aug 26 '18 at 20:48






        • 1





          @Mr_and_Mrs_D , I've updated the post with an example with functool.wraps. Adding it in the example may confuse readers further.

          – srj
          Aug 28 '18 at 2:31






        • 2





          What is arg here!?

          – displayname
          Sep 25 '18 at 10:22








        1




        1





        Your answer perfectly explained the inherent orthogonality of the decorator, thank you

        – zsf222
        Dec 9 '17 at 15:58





        Your answer perfectly explained the inherent orthogonality of the decorator, thank you

        – zsf222
        Dec 9 '17 at 15:58




        1




        1





        life saving answer!.

        – saiteja pakalapati
        Jul 12 '18 at 11:51





        life saving answer!.

        – saiteja pakalapati
        Jul 12 '18 at 11:51













        Could you add @functools.wraps?

        – Mr_and_Mrs_D
        Aug 26 '18 at 20:48





        Could you add @functools.wraps?

        – Mr_and_Mrs_D
        Aug 26 '18 at 20:48




        1




        1





        @Mr_and_Mrs_D , I've updated the post with an example with functool.wraps. Adding it in the example may confuse readers further.

        – srj
        Aug 28 '18 at 2:31





        @Mr_and_Mrs_D , I've updated the post with an example with functool.wraps. Adding it in the example may confuse readers further.

        – srj
        Aug 28 '18 at 2:31




        2




        2





        What is arg here!?

        – displayname
        Sep 25 '18 at 10:22





        What is arg here!?

        – displayname
        Sep 25 '18 at 10:22











        66














        I'd like to show an idea which is IMHO quite elegant. The solution proposed by t.dubrownik shows a pattern which is always the same: you need the three-layered wrapper regardless of what the decorator does.



        So I thought this is a job for a meta-decorator, that is, a decorator for decorators. As a decorator is a function, it actually works as a regular decorator with arguments:



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


        This can be applied to a regular decorator in order to add parameters. So for instance, say we have the decorator which doubles the result of a function:



        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)


        With @parametrized we can build a generic @multiply decorator having a parameter



        @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)


        Conventionally the first parameter of a parametrized decorator is the function, while the remaining arguments will correspond to the parameter of the parametrized decorator.



        An interesting usage example could be a type-safe assertive decorator:



        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


        A final note: here I'm not using functools.wraps for the wrapper functions, but I would recommend using it all the times.






        share|improve this answer


























        • Didn't use this exactly, but helped me get my head around the concept :) Thanks!

          – mouckatron
          Oct 10 '17 at 22:04











        • I tried this and had some issues.

          – Jeff
          Oct 14 '17 at 14:53













        • @Jeff could you share with us the kind of issues you had?

          – Dacav
          Oct 14 '17 at 16:49











        • I had it linked on my question, and I did figure it out... I needed to call @wraps in mine for my particular case.

          – Jeff
          Oct 14 '17 at 19:33






        • 3





          Oh boy, I lost a whole day on this. Thankfully, I came around this answer (which incidentally could be the best answer ever created on the whole internet). They too use your @parametrized trick. The problem I had was I forgot the @ syntax equals actual calls (somehow I knew that and didn't know that at the same time as you can gather from my question). So if you want to translate @ syntax into mundane calls to check how it works, you better comment it out temporarily first or you'd end up calling it twice and getting mumbojumbo results

          – z33k
          Mar 13 '18 at 14:50


















        66














        I'd like to show an idea which is IMHO quite elegant. The solution proposed by t.dubrownik shows a pattern which is always the same: you need the three-layered wrapper regardless of what the decorator does.



        So I thought this is a job for a meta-decorator, that is, a decorator for decorators. As a decorator is a function, it actually works as a regular decorator with arguments:



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


        This can be applied to a regular decorator in order to add parameters. So for instance, say we have the decorator which doubles the result of a function:



        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)


        With @parametrized we can build a generic @multiply decorator having a parameter



        @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)


        Conventionally the first parameter of a parametrized decorator is the function, while the remaining arguments will correspond to the parameter of the parametrized decorator.



        An interesting usage example could be a type-safe assertive decorator:



        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


        A final note: here I'm not using functools.wraps for the wrapper functions, but I would recommend using it all the times.






        share|improve this answer


























        • Didn't use this exactly, but helped me get my head around the concept :) Thanks!

          – mouckatron
          Oct 10 '17 at 22:04











        • I tried this and had some issues.

          – Jeff
          Oct 14 '17 at 14:53













        • @Jeff could you share with us the kind of issues you had?

          – Dacav
          Oct 14 '17 at 16:49











        • I had it linked on my question, and I did figure it out... I needed to call @wraps in mine for my particular case.

          – Jeff
          Oct 14 '17 at 19:33






        • 3





          Oh boy, I lost a whole day on this. Thankfully, I came around this answer (which incidentally could be the best answer ever created on the whole internet). They too use your @parametrized trick. The problem I had was I forgot the @ syntax equals actual calls (somehow I knew that and didn't know that at the same time as you can gather from my question). So if you want to translate @ syntax into mundane calls to check how it works, you better comment it out temporarily first or you'd end up calling it twice and getting mumbojumbo results

          – z33k
          Mar 13 '18 at 14:50
















        66












        66








        66







        I'd like to show an idea which is IMHO quite elegant. The solution proposed by t.dubrownik shows a pattern which is always the same: you need the three-layered wrapper regardless of what the decorator does.



        So I thought this is a job for a meta-decorator, that is, a decorator for decorators. As a decorator is a function, it actually works as a regular decorator with arguments:



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


        This can be applied to a regular decorator in order to add parameters. So for instance, say we have the decorator which doubles the result of a function:



        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)


        With @parametrized we can build a generic @multiply decorator having a parameter



        @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)


        Conventionally the first parameter of a parametrized decorator is the function, while the remaining arguments will correspond to the parameter of the parametrized decorator.



        An interesting usage example could be a type-safe assertive decorator:



        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


        A final note: here I'm not using functools.wraps for the wrapper functions, but I would recommend using it all the times.






        share|improve this answer















        I'd like to show an idea which is IMHO quite elegant. The solution proposed by t.dubrownik shows a pattern which is always the same: you need the three-layered wrapper regardless of what the decorator does.



        So I thought this is a job for a meta-decorator, that is, a decorator for decorators. As a decorator is a function, it actually works as a regular decorator with arguments:



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


        This can be applied to a regular decorator in order to add parameters. So for instance, say we have the decorator which doubles the result of a function:



        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)


        With @parametrized we can build a generic @multiply decorator having a parameter



        @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)


        Conventionally the first parameter of a parametrized decorator is the function, while the remaining arguments will correspond to the parameter of the parametrized decorator.



        An interesting usage example could be a type-safe assertive decorator:



        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


        A final note: here I'm not using functools.wraps for the wrapper functions, but I would recommend using it all the times.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited May 20 '18 at 12:39









        Peter Mortensen

        13.6k1984111




        13.6k1984111










        answered Oct 1 '14 at 22:17









        DacavDacav

        6,96144469




        6,96144469













        • Didn't use this exactly, but helped me get my head around the concept :) Thanks!

          – mouckatron
          Oct 10 '17 at 22:04











        • I tried this and had some issues.

          – Jeff
          Oct 14 '17 at 14:53













        • @Jeff could you share with us the kind of issues you had?

          – Dacav
          Oct 14 '17 at 16:49











        • I had it linked on my question, and I did figure it out... I needed to call @wraps in mine for my particular case.

          – Jeff
          Oct 14 '17 at 19:33






        • 3





          Oh boy, I lost a whole day on this. Thankfully, I came around this answer (which incidentally could be the best answer ever created on the whole internet). They too use your @parametrized trick. The problem I had was I forgot the @ syntax equals actual calls (somehow I knew that and didn't know that at the same time as you can gather from my question). So if you want to translate @ syntax into mundane calls to check how it works, you better comment it out temporarily first or you'd end up calling it twice and getting mumbojumbo results

          – z33k
          Mar 13 '18 at 14:50





















        • Didn't use this exactly, but helped me get my head around the concept :) Thanks!

          – mouckatron
          Oct 10 '17 at 22:04











        • I tried this and had some issues.

          – Jeff
          Oct 14 '17 at 14:53













        • @Jeff could you share with us the kind of issues you had?

          – Dacav
          Oct 14 '17 at 16:49











        • I had it linked on my question, and I did figure it out... I needed to call @wraps in mine for my particular case.

          – Jeff
          Oct 14 '17 at 19:33






        • 3





          Oh boy, I lost a whole day on this. Thankfully, I came around this answer (which incidentally could be the best answer ever created on the whole internet). They too use your @parametrized trick. The problem I had was I forgot the @ syntax equals actual calls (somehow I knew that and didn't know that at the same time as you can gather from my question). So if you want to translate @ syntax into mundane calls to check how it works, you better comment it out temporarily first or you'd end up calling it twice and getting mumbojumbo results

          – z33k
          Mar 13 '18 at 14:50



















        Didn't use this exactly, but helped me get my head around the concept :) Thanks!

        – mouckatron
        Oct 10 '17 at 22:04





        Didn't use this exactly, but helped me get my head around the concept :) Thanks!

        – mouckatron
        Oct 10 '17 at 22:04













        I tried this and had some issues.

        – Jeff
        Oct 14 '17 at 14:53







        I tried this and had some issues.

        – Jeff
        Oct 14 '17 at 14:53















        @Jeff could you share with us the kind of issues you had?

        – Dacav
        Oct 14 '17 at 16:49





        @Jeff could you share with us the kind of issues you had?

        – Dacav
        Oct 14 '17 at 16:49













        I had it linked on my question, and I did figure it out... I needed to call @wraps in mine for my particular case.

        – Jeff
        Oct 14 '17 at 19:33





        I had it linked on my question, and I did figure it out... I needed to call @wraps in mine for my particular case.

        – Jeff
        Oct 14 '17 at 19:33




        3




        3





        Oh boy, I lost a whole day on this. Thankfully, I came around this answer (which incidentally could be the best answer ever created on the whole internet). They too use your @parametrized trick. The problem I had was I forgot the @ syntax equals actual calls (somehow I knew that and didn't know that at the same time as you can gather from my question). So if you want to translate @ syntax into mundane calls to check how it works, you better comment it out temporarily first or you'd end up calling it twice and getting mumbojumbo results

        – z33k
        Mar 13 '18 at 14:50







        Oh boy, I lost a whole day on this. Thankfully, I came around this answer (which incidentally could be the best answer ever created on the whole internet). They too use your @parametrized trick. The problem I had was I forgot the @ syntax equals actual calls (somehow I knew that and didn't know that at the same time as you can gather from my question). So if you want to translate @ syntax into mundane calls to check how it works, you better comment it out temporarily first or you'd end up calling it twice and getting mumbojumbo results

        – z33k
        Mar 13 '18 at 14:50













        51














        Here is a slightly modified version of t.dubrownik's answer. Why?




        1. As a general template, you should return the return value from the original function.

        2. This changes the name of the function, which could affect other decorators / code.


        So use @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





        share|improve this answer






























          51














          Here is a slightly modified version of t.dubrownik's answer. Why?




          1. As a general template, you should return the return value from the original function.

          2. This changes the name of the function, which could affect other decorators / code.


          So use @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





          share|improve this answer




























            51












            51








            51







            Here is a slightly modified version of t.dubrownik's answer. Why?




            1. As a general template, you should return the return value from the original function.

            2. This changes the name of the function, which could affect other decorators / code.


            So use @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





            share|improve this answer















            Here is a slightly modified version of t.dubrownik's answer. Why?




            1. As a general template, you should return the return value from the original function.

            2. This changes the name of the function, which could affect other decorators / code.


            So use @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






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jun 22 '18 at 10:44









            fedorqui

            167k53341381




            167k53341381










            answered Mar 3 '17 at 14:11









            Ross RRoss R

            2,46742124




            2,46742124























                35














                I presume your problem is passing arguments to your decorator. This is a little tricky and not straightforward.



                Here's an example of how to do this:



                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')


                Prints:



                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


                See Bruce Eckel's article for more details.






                share|improve this answer





















                • 19





                  Beware of decorator classes. They don't work on methods unless you manually reinvent the logic of instancemethod descriptors.

                  – user395760
                  May 8 '11 at 18:01






                • 9





                  delnan, care to elaborate? I've only had to use this pattern once, so I haven't hit any of the pitfalls yet.

                  – Ross Rogers
                  May 8 '11 at 18:04








                • 2





                  @RossRogers My guess is that @delnan is referring to things like __name__ which an instance of the decorator class won't have?

                  – jamesc
                  Jan 13 '14 at 17:18






                • 9





                  @jamesc That too, though that's relatively easy to solve. The specific case I was referring to was class Foo: @MyDec(...) def method(self, ...): blah which does not work because Foo().method won't be a bound method and won't pass self automatically. This too can be fixed, by making MyDec a descriptor and creating bound methods in __get__, but it's more involved and much less obvious. In the end, decorator classes are not as convenient as they seem.

                  – user395760
                  Jan 13 '14 at 21:49








                • 2





                  @delnan I'd like to see this caveat featured more prominently. I'm hitting it and am interested in seeing a solution that DOES work (more involved an less obvious though it may be).

                  – HaPsantran
                  Mar 13 '16 at 6:42
















                35














                I presume your problem is passing arguments to your decorator. This is a little tricky and not straightforward.



                Here's an example of how to do this:



                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')


                Prints:



                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


                See Bruce Eckel's article for more details.






                share|improve this answer





















                • 19





                  Beware of decorator classes. They don't work on methods unless you manually reinvent the logic of instancemethod descriptors.

                  – user395760
                  May 8 '11 at 18:01






                • 9





                  delnan, care to elaborate? I've only had to use this pattern once, so I haven't hit any of the pitfalls yet.

                  – Ross Rogers
                  May 8 '11 at 18:04








                • 2





                  @RossRogers My guess is that @delnan is referring to things like __name__ which an instance of the decorator class won't have?

                  – jamesc
                  Jan 13 '14 at 17:18






                • 9





                  @jamesc That too, though that's relatively easy to solve. The specific case I was referring to was class Foo: @MyDec(...) def method(self, ...): blah which does not work because Foo().method won't be a bound method and won't pass self automatically. This too can be fixed, by making MyDec a descriptor and creating bound methods in __get__, but it's more involved and much less obvious. In the end, decorator classes are not as convenient as they seem.

                  – user395760
                  Jan 13 '14 at 21:49








                • 2





                  @delnan I'd like to see this caveat featured more prominently. I'm hitting it and am interested in seeing a solution that DOES work (more involved an less obvious though it may be).

                  – HaPsantran
                  Mar 13 '16 at 6:42














                35












                35








                35







                I presume your problem is passing arguments to your decorator. This is a little tricky and not straightforward.



                Here's an example of how to do this:



                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')


                Prints:



                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


                See Bruce Eckel's article for more details.






                share|improve this answer















                I presume your problem is passing arguments to your decorator. This is a little tricky and not straightforward.



                Here's an example of how to do this:



                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')


                Prints:



                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


                See Bruce Eckel's article for more details.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited May 20 '18 at 12:37









                Peter Mortensen

                13.6k1984111




                13.6k1984111










                answered May 8 '11 at 17:56









                Ross RogersRoss Rogers

                11.7k1683138




                11.7k1683138








                • 19





                  Beware of decorator classes. They don't work on methods unless you manually reinvent the logic of instancemethod descriptors.

                  – user395760
                  May 8 '11 at 18:01






                • 9





                  delnan, care to elaborate? I've only had to use this pattern once, so I haven't hit any of the pitfalls yet.

                  – Ross Rogers
                  May 8 '11 at 18:04








                • 2





                  @RossRogers My guess is that @delnan is referring to things like __name__ which an instance of the decorator class won't have?

                  – jamesc
                  Jan 13 '14 at 17:18






                • 9





                  @jamesc That too, though that's relatively easy to solve. The specific case I was referring to was class Foo: @MyDec(...) def method(self, ...): blah which does not work because Foo().method won't be a bound method and won't pass self automatically. This too can be fixed, by making MyDec a descriptor and creating bound methods in __get__, but it's more involved and much less obvious. In the end, decorator classes are not as convenient as they seem.

                  – user395760
                  Jan 13 '14 at 21:49








                • 2





                  @delnan I'd like to see this caveat featured more prominently. I'm hitting it and am interested in seeing a solution that DOES work (more involved an less obvious though it may be).

                  – HaPsantran
                  Mar 13 '16 at 6:42














                • 19





                  Beware of decorator classes. They don't work on methods unless you manually reinvent the logic of instancemethod descriptors.

                  – user395760
                  May 8 '11 at 18:01






                • 9





                  delnan, care to elaborate? I've only had to use this pattern once, so I haven't hit any of the pitfalls yet.

                  – Ross Rogers
                  May 8 '11 at 18:04








                • 2





                  @RossRogers My guess is that @delnan is referring to things like __name__ which an instance of the decorator class won't have?

                  – jamesc
                  Jan 13 '14 at 17:18






                • 9





                  @jamesc That too, though that's relatively easy to solve. The specific case I was referring to was class Foo: @MyDec(...) def method(self, ...): blah which does not work because Foo().method won't be a bound method and won't pass self automatically. This too can be fixed, by making MyDec a descriptor and creating bound methods in __get__, but it's more involved and much less obvious. In the end, decorator classes are not as convenient as they seem.

                  – user395760
                  Jan 13 '14 at 21:49








                • 2





                  @delnan I'd like to see this caveat featured more prominently. I'm hitting it and am interested in seeing a solution that DOES work (more involved an less obvious though it may be).

                  – HaPsantran
                  Mar 13 '16 at 6:42








                19




                19





                Beware of decorator classes. They don't work on methods unless you manually reinvent the logic of instancemethod descriptors.

                – user395760
                May 8 '11 at 18:01





                Beware of decorator classes. They don't work on methods unless you manually reinvent the logic of instancemethod descriptors.

                – user395760
                May 8 '11 at 18:01




                9




                9





                delnan, care to elaborate? I've only had to use this pattern once, so I haven't hit any of the pitfalls yet.

                – Ross Rogers
                May 8 '11 at 18:04







                delnan, care to elaborate? I've only had to use this pattern once, so I haven't hit any of the pitfalls yet.

                – Ross Rogers
                May 8 '11 at 18:04






                2




                2





                @RossRogers My guess is that @delnan is referring to things like __name__ which an instance of the decorator class won't have?

                – jamesc
                Jan 13 '14 at 17:18





                @RossRogers My guess is that @delnan is referring to things like __name__ which an instance of the decorator class won't have?

                – jamesc
                Jan 13 '14 at 17:18




                9




                9





                @jamesc That too, though that's relatively easy to solve. The specific case I was referring to was class Foo: @MyDec(...) def method(self, ...): blah which does not work because Foo().method won't be a bound method and won't pass self automatically. This too can be fixed, by making MyDec a descriptor and creating bound methods in __get__, but it's more involved and much less obvious. In the end, decorator classes are not as convenient as they seem.

                – user395760
                Jan 13 '14 at 21:49







                @jamesc That too, though that's relatively easy to solve. The specific case I was referring to was class Foo: @MyDec(...) def method(self, ...): blah which does not work because Foo().method won't be a bound method and won't pass self automatically. This too can be fixed, by making MyDec a descriptor and creating bound methods in __get__, but it's more involved and much less obvious. In the end, decorator classes are not as convenient as they seem.

                – user395760
                Jan 13 '14 at 21:49






                2




                2





                @delnan I'd like to see this caveat featured more prominently. I'm hitting it and am interested in seeing a solution that DOES work (more involved an less obvious though it may be).

                – HaPsantran
                Mar 13 '16 at 6:42





                @delnan I'd like to see this caveat featured more prominently. I'm hitting it and am interested in seeing a solution that DOES work (more involved an less obvious though it may be).

                – HaPsantran
                Mar 13 '16 at 6:42











                1














                In my instance, I decided to solve this via a one-line lambda to create a new decorator function:



                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()


                When executed, this prints:



                Finished!
                All Done!


                Perhaps not as extensible as other solutions, but worked for me.






                share|improve this answer
























                • This works. Although yes, this makes it hard to set the value to the decorator.

                  – Arindam Roychowdhury
                  Jan 11 at 11:28
















                1














                In my instance, I decided to solve this via a one-line lambda to create a new decorator function:



                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()


                When executed, this prints:



                Finished!
                All Done!


                Perhaps not as extensible as other solutions, but worked for me.






                share|improve this answer
























                • This works. Although yes, this makes it hard to set the value to the decorator.

                  – Arindam Roychowdhury
                  Jan 11 at 11:28














                1












                1








                1







                In my instance, I decided to solve this via a one-line lambda to create a new decorator function:



                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()


                When executed, this prints:



                Finished!
                All Done!


                Perhaps not as extensible as other solutions, but worked for me.






                share|improve this answer













                In my instance, I decided to solve this via a one-line lambda to create a new decorator function:



                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()


                When executed, this prints:



                Finished!
                All Done!


                Perhaps not as extensible as other solutions, but worked for me.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Jun 15 '18 at 19:21









                ZacBookZacBook

                111




                111













                • This works. Although yes, this makes it hard to set the value to the decorator.

                  – Arindam Roychowdhury
                  Jan 11 at 11:28



















                • This works. Although yes, this makes it hard to set the value to the decorator.

                  – Arindam Roychowdhury
                  Jan 11 at 11:28

















                This works. Although yes, this makes it hard to set the value to the decorator.

                – Arindam Roychowdhury
                Jan 11 at 11:28





                This works. Although yes, this makes it hard to set the value to the decorator.

                – Arindam Roychowdhury
                Jan 11 at 11:28











                0














                define this "decoratorize function" to generate customized decorator function:



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


                use it this way:



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





                share|improve this answer




























                  0














                  define this "decoratorize function" to generate customized decorator function:



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


                  use it this way:



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





                  share|improve this answer


























                    0












                    0








                    0







                    define this "decoratorize function" to generate customized decorator function:



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


                    use it this way:



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





                    share|improve this answer













                    define this "decoratorize function" to generate customized decorator function:



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


                    use it this way:



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






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Oct 30 '18 at 5:40









                    chen.wqchen.wq

                    62




                    62























                        0














                        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


                        Usage of the decorator



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


                        Then the



                        adder(2,3)


                        produces



                        10


                        but



                        adder('hi',3)


                        produces



                        ---------------------------------------------------------------------------
                        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





                        share|improve this answer




























                          0














                          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


                          Usage of the decorator



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


                          Then the



                          adder(2,3)


                          produces



                          10


                          but



                          adder('hi',3)


                          produces



                          ---------------------------------------------------------------------------
                          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





                          share|improve this answer


























                            0












                            0








                            0







                            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


                            Usage of the decorator



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


                            Then the



                            adder(2,3)


                            produces



                            10


                            but



                            adder('hi',3)


                            produces



                            ---------------------------------------------------------------------------
                            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





                            share|improve this answer













                            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


                            Usage of the decorator



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


                            Then the



                            adder(2,3)


                            produces



                            10


                            but



                            adder('hi',3)


                            produces



                            ---------------------------------------------------------------------------
                            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






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Dec 29 '18 at 21:57









                            Gajendra D AmbiGajendra D Ambi

                            9811115




                            9811115






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f5929107%2fdecorators-with-parameters%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                eRSCy4yt5HfGSPhXoLCaqg6sykQq9p T60aOsN LGN
                                ArjVXX

                                Popular posts from this blog

                                Monofisismo

                                Angular Downloading a file using contenturl with Basic Authentication

                                Olmecas