tags:

views:

115

answers:

3

This is python 2.5, it's GAE too not that it matters.

I have the following code, I'm decorating the foo() method in bar, using the dec_check class as a decorator.

class dec_check(object):

  def __init__(self, f):
    self.func = f 

  def __call__(self):
    print 'In auth_check.__init__()'
    self.func()

class bar(object):

  @dec_check
  def foo(self):
    print 'In bar.foo()'

b = bar()
b.foo()

When executing this I was hoping to see:

In dec_check.__init__()
In bar.foo()

But I'm getting "TypeError: foo() takes exactly 1 argument (0 given)" as foo() being an object method takes self as an argument. I'm guessing problem is that the instance of bar doesn't actually exist when I'm executing the decorator code. So how do I pass an instance of bar to the decorator class?

+1  A: 

Decorators can be a little tricky in Python. Here's an example of one I got to work sometime back. You might be able to infer from it what you're trying to do.

http://stackoverflow.com/questions/312925/django-authentication-and-ajax-urls-that-require-login/523196#523196

Eric W.
+5  A: 

You need to make the decorator into a descriptor -- either by ensuring its (meta)class has a __get__ method, or, way simpler, by using a decorator function instead of a decorator class (since functions are already descriptors). E.g.:

def dec_check(f):
  def deco(self):
    print 'In deco'
    f(self)
  return deco

class bar(object):
  @dec_check
  def foo(self):
    print 'in bar.foo'

b = bar()
b.foo()

this prints

In deco
in bar.foo

as desired.

Alex Martelli
Heh, its easy when you know how. Thanks Alex.
Phil
@Phil, you're welcome!
Alex Martelli
A: 

Alex's answer suffices when a function is sufficient. However When you need a class you can make it work by adding the following method to the decorator class.

def __get__(self, obj, objtype):
    """Support instance methods."""
    import functools
    return functools.partial(self.__call__, obj)
tolomea