Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Decorators and inheritance

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?

like image 356
wheaties Avatar asked Jun 08 '10 20:06

wheaties


People also ask

What are Python decorators used for?

A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.

When should I use Python decorators?

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. You can also use one when you need to run the same code on multiple functions.

Are Python decorators necessary?

Python is praised for its clear and concise syntax, and decorators are no exceptions. If there is any behaviour that is common to more than one function, you probably need to make a decorator. Here are some examples when they might come in handy: Check arguments type at runtime.


2 Answers

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
like image 88
Pär Wieslander Avatar answered Sep 27 '22 18:09

Pär Wieslander


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
like image 30
Sitrus Avatar answered Sep 27 '22 18:09

Sitrus