1
def lowercasewrapper(func):
    def wrapper(*args, **kwargs):
        return [item.lower() for item in func(*args, **kwargs)]
    return wrapper

I understand what decorators do, I have implemented the decorator above into my code and it works, but I'm little unsure about a few things.

  1. Why can't (func) be replaced by (*args, **kwargs) and in the process remove the def wrapper line? I'm guessing the first 2 lines don't do the same thing, but to me that's what it seems like. It seems like:

    def lowercasewrapper(accept function) 
        def wrapper(accept function)
    
  2. What is the significance of the word 'func' here? I noticed I can replace that word with anything and my code still works. Does the function I put below @lowercasewrapper just feed into the decorator regardless of whats in the '( )'?

  3. Also, a little off topic but the word item also has no significance right? I can replace that with any word as well and it still works.

I would appreciate if anyone would try to help and explain and answer in detail instead of redirecting me to a "what's a decorator" thread.

stephan
  • 2,293
  • 4
  • 31
  • 55
  • 1
    Maybe this [awesome post about python decorators](http://stackoverflow.com/a/1594484/1461780) would be helpful. – Leon Young Oct 27 '13 at 04:43

1 Answers1

3

The short version is that a decorator actually turns this:

@decorated
def f(*args):
    # function body

Into this:

def f(*args):
    # function body
f = decorated(f)

So the reason you need the inner function is that the decorator must return a function, or the above makes no sense. With that in mind:

Point 1: notice that the last line returns wrapper, as in the function wrapper itself. This is why you can't remove that part; the function is actually building an altered function to return.

Points 2 and 3: You're right, it's just an arbitrary variable name and has no meaning outside this function.

So! With that in mind, here's what's going on in the decorator:

  • lowercasewrapper(f) is called (where f is apparently assumed to return an iterable of strings)
  • lowercasewrapper defines another function that takes some arbitrary arguments, then calls f on those arguments, then returns the result but with the items converted to lowercase
  • lowercasewrapper then returns the altered function

The biggest obstacle here is likely to be the idea of returning a function as opposed to returning the result of calling a function. Read up on first-class functions (or see Leon Young's link) if this makes no sense to you.

Free Monica Cellio
  • 2,270
  • 1
  • 16
  • 15
  • Kind of makes more sense now. So the 4 lines are basically 1. Take in the decorated function. 2. take in the arguments from the decorated function and do whatever. 3. return the arguments 4. return the altered function? – stephan Oct 27 '13 at 05:16
  • Well, I'd alter that a little bit to say: 1: Take in the decorated function 2: Build an altered function that accepts the same arguments as the decorated function and does whatever 3: Return the altered function. Notice that when the altered `wrapper` function is called it just passes its arguments to `func` unaltered so it doesn't actually have to know or care what those arguments are. – Free Monica Cellio Oct 27 '13 at 05:23