3

Through searching I have found many tutorials that explain how it works but not why it works that way. I know now how to implement all the 3 main use cases:

  • 1st: no arguments involved
  • 2nd: the function that I want to decorate has arguments
  • 3rd: the decorator itself has arguments

I find the first and second use case very intuitive: Python sees a decorator and it says "okay decorator, here's your function - hands over the argument -, now gimme something that I can use instead".

1st use case: "You gave me a function that takes no arguments? Works, thanks".

2nd use case: "You gave me a function that just takes *args and **kwargs? Works, thanks

Now the 3rd use case with example code:

def mydecorator(msg=""):
    def wrapper2(func):
        def wrapper(*args, **kwargs):
            func(*args, **kwargs)
            print "You know nothing about Python"
            print msg
        return wrapper
    return wrapper2

@mydecorator(msg="No, really, nothing.")
def printHello(name="Jon Snow"):
    print "Hello " + name

I don't understand the internal logic of this one. In this case python cannot say "Hey decorator, here's the function, gimme something that I can use instead". This time python says "Here's your msg argument, now gimme a function that I can use instead of the function which I haven't told you (because I gave you msg instead)". So how can the decorator now get/work with func if it gets msg instead of func?

E_net4
  • 27,810
  • 13
  • 101
  • 139
user3182532
  • 1,097
  • 5
  • 22
  • 37
  • 1
    The third decorator returns `wrapper2` after you pass the argument `msg`. It is `wrapper2` that you're feeding the function `printHello` to. That is how all decorators work. – Akshat Mahajan Jul 22 '17 at 18:09
  • 1
    `mydecorator ` isn't a decorator, it's a decorator factory. `wrapper2` is the decorator that receives the actual function and wraps it within `wrapper`. – Ashwini Chaudhary Jul 22 '17 at 18:13
  • I wish it hadn't been designed this way - it means `@deco` and `@deco()` do completely different things, which makes decorators with optional arguments really awkward, especially if you're adding optional arguments to a decorator that originally never took arguments. – user2357112 Jul 22 '17 at 18:16
  • @user2357112: How else would you do it? The way to think about it is that it is basically `@expression`, and the result of `expression` is what is called with the function as an argument. So `expression` can be either the decorator or something that returns the decorator. (In fact there are restrictions so that not all expressions can be used as a decorator, but that's the basic idea.) Also, note that the inner function `wrapper` in your example can also access the `msg` variable. – BrenBarn Jul 22 '17 at 18:20
  • @BrenBarn: I'd insert the function at the front of the decorator's argument list, sort of like how `self` is implicitly inserted at the front of a method's argument list. `@something` would call `something(func)`, `@something()` would also call `something(func)`, and `@something(some, args)` would call `something(func, some, args)`. – user2357112 Jul 22 '17 at 18:29
  • If you're encountering awkwardness writing a decorator it might be good to ask about that problem specifically. It's true, though, that decorators without arguments work different than those with arguments, so changing from no-arguments to some-arguments requires reshuffling things a bit. I'm not sure what you mean about optional arguments though. – BrenBarn Jul 22 '17 at 18:54
  • @BrenBarn: I'm not the questioner - you can tell because I don't have the blue background. As for optional arguments, I'm talking about decorators like `functools.lru_cache` that take 0 or more arguments: `@functools.lru_cache()` or `@functools.lru_cache(maxsize=16)` or `@functools.lru_cache(typed=True)` or whatever. – user2357112 Jul 22 '17 at 21:08
  • Due to the way decorator syntax is designed, such a decorator can't be used as `@functools.lru_cache`, and if you want to *add* optional arguments to a decorator previously used as `@foo`, your options for doing that are really awkward. – user2357112 Jul 22 '17 at 21:14

0 Answers0