Mark Mark - 4 months ago 23
Python Question

Python class method decorator w/ self arguments?

How do I pass a class field to a decorator on a class method as an argument? What I want to do is something like:

class Client(object):
def __init__(self, url):
self.url = url

@check_authorization("some_attr", self.url)
def get(self):
do_work()


It complains that self doesn't exist for passing self.url to the decorator. Is there a way around this?

Answer

Yes. Instead of passing in the instance attribute at class definition time, check it at runtime:

def check_authorization(f):
    def wrapper(*args):
        print args[0].url
        return f(*args)
    return wrapper

class Client(object):
    def __init__(self, url):
        self.url = url

    @check_authorization
    def get(self):
        print 'get'

>>> Client('http://www.google.com').get()
http://www.google.com
get

The decorator intercepts the method arguments; the first argument is the instance, so it reads the attribute off of that. You can pass in the attribute name as a string to the decorator and use getattr if you don't want to hardcode the attribute name:

def check_authorization(attribute):
    def _check_authorization(f):
        def wrapper(self, *args):
            print getattr(self, attribute)
            return f(self, *args)
        return wrapper
    return _check_authorization