Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use named arguments in a decorator?

If I have the following function:


def intercept(func):
  # do something here

@intercept(arg1=20)
def whatever(arg1,arg2):
  # do something here

I would like for intercept to fire up only when arg1 is 20. I would like to be able to pass named parameters to the function. How could I accomplish this?

Here's a little code sample :



def intercept(func):
    def intercepting_func(*args,**kargs):
        print "whatever"
        return func(*args,**kargs)
    return intercepting_func

@intercept(a="g")
def test(a,b):
    print "test with %s %s" %(a,b)

test("g","d")

This throws the following exception TypeError: intercept() got an unexpected keyword argument 'a'

like image 926
Geo Avatar asked Mar 09 '09 18:03

Geo


People also ask

Can decorator have arguments?

The decorator arguments are accessible to the inner decorator through a closure, exactly like how the wrapped() inner function can access f . And since closures extend to all the levels of inner functions, arg is also accessible from within wrapped() if necessary.

How do you pass a named argument in Python?

Keyword arguments (or named arguments) are values that, when passed into a function, are identifiable by specific parameter names. A keyword argument is preceded by a parameter and the assignment operator, = . Keyword arguments can be likened to dictionaries in that they map a value to a keyword.

Can you give a good use case for using a decorator in Python?

When to Use a Decorator in Python. You'll use a decorator when you need to change the behavior of a function without modifying the function itself. A few good examples are when you want to add logging, test performance, perform caching, verify permissions, and so on.


1 Answers

Remember that

@foo
def bar():
    pass

is equivalent to:

def bar():
    pass
bar = foo(bar)

so if you do:

@foo(x=3)
def bar():
    pass

that's equivalent to:

def bar():
    pass
bar = foo(x=3)(bar)

so your decorator needs to look something like this:

def foo(x=1):
    def wrap(f):
        def f_foo(*args, **kw):
            # do something to f
            return f(*args, **kw)
        return f_foo
    return wrap

In other words, def wrap(f) is really the decorator, and foo(x=3) is a function call that returns a decorator.

like image 115
John Fouhy Avatar answered Oct 12 '22 04:10

John Fouhy