24

Help a guy out. Can't seem to get a decorator to work with inheritance. Broke it down to the simplest little example in my scratch workspace. Still can't seem to get it working.

class bar(object):
    def __init__(self):
        self.val = 4
    def setVal(self,x):
        self.val = x
    def decor(self, func):
        def increment(self, x):
            return func( self, x ) + self.val
        return increment

class foo(bar):
    def __init__(self):
        bar.__init__(self)
    @decor
    def add(self, x):
        return x

Oops, name "decor" is not defined.

Okay, how about @bar.decor? TypeError: unbound method "decor" must be called with a bar instance as first argument (got function instance instead)

Ok, how about @self.decor? Name "self" is not defined.

Ok, how about @foo.decor?! Name "foo" is not defined.

AaaaAAaAaaaarrrrgggg... What am I doing wrong?

wheaties
  • 35,646
  • 15
  • 94
  • 131
  • In your example, you could have `return x + self.val` for the definition of `add` in `foo`. Could you not do this in you actual code? – Gary Kerr Jun 08 '10 at 20:52
  • This is a distilled example code highlighting the issue I was facing. If the code were that simple, then yes. However, it's not. – wheaties Jun 08 '10 at 21:04

2 Answers2

27

Define decor as a static method and use the form @bar.decor:

class bar(object):
    def __init__(self):
        self.val = 4
    def setVal(self,x):
        self.val = x
    @staticmethod
    def decor(func):
        def increment(self, x):
            return func(self, x) + self.val
        return increment

class foo(bar):
    def __init__(self):
        bar.__init__(self)
    @bar.decor
    def add(self, x):
        return x
Pär Wieslander
  • 28,374
  • 7
  • 55
  • 54
  • This works even better because `self` isn't used in both function definitions. – exupero Jun 08 '10 at 21:00
  • 1
    @EShull: Actually, `decor` can be a static method, despite the `self` reference. `self` is only referenced inside `increment()`, and when invoking `f.add(10)` on a `foo` instance, the `self` parameter inside `increment()` will reference `f`, and the increment will work as expected. – Pär Wieslander Jun 08 '10 at 21:07
  • This looks like it'll work. Gotta leave work but if it does, I'm going to flag this as the answer. Thanks! – wheaties Jun 08 '10 at 21:23
  • 2
    Does this currently work? Does it not raise a `TypeError: staticmethod is not callable`? –  Sep 12 '18 at 09:43
2

I know the question has been asked 11 years ago ...

I had the same problem, here is my solution to use an inherited private decorator :

class foo:
    def __bar(func):
        def wrapper(self):
            print('beginning')
            func(self)
            print('end')
        return wrapper

class baz(foo):
    def __init__(self):
        self.quux = 'middle'
    @foo._foo__bar
    def qux(self):
        print(self.quux)

a = baz()
a.qux()

The output is :

beginning
middle
end
Sitrus
  • 31
  • 1