Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python method decorator to access an instance variable

I have a Python class that has a couple of state variables - let's call them self.state and self.process:

class MyClass(object):
    def __init__(state=None, process=None):
        self.state = state
        self.process = process

Now, I have a LOT of methods that should yield an error if self.state and self.process are none. I don't want to have to handcode a test for each, so I was thinking, I'll do a decorator - something like this:

class MyClass(object):
    ...

    @needs_state
    def some_function():
        # do something

Now if some_function() is called but self.state is None, an error will be raised. Can I accomplish this with decorators - ideally just with one? (I've seen the solution that uses a class decorator and I'm not sure it does what I wish it did!). Bonus points for a good explanation for why I cannot ;)

like image 863
Chris vCB Avatar asked Oct 23 '25 05:10

Chris vCB


1 Answers

Decorators are ordinary functions, and self is no exception to the rule. So let's say I write a decorator function that takes an argument called self:

def needs_state(fn):
    def decorator(self, *args, **kwargs):
        if self.state is None:
            raise ValueError('Oh no')
        return fn(self, *args, **kwargs)
    return decorator

It does not know what self is, because it is not in a class, but that's okay, you can use the decorator in a class, in the way you expect.

class MyClass(object):

    def __init__(self, state=None):
        self.state = state

    @needs_state
    def some_function(self):
        print self.state

So, if you now instantiate the class with anything, your some_function will first check if self.state is none, because you had just decorated it. Similarly, if the class does not have a state, then the exception is raised as expected.

MyClass(1).some_function()  # 1
MyClass(None).some_function()  # raises

self.process is left out so you need to do some work.

like image 98
Brian Avatar answered Oct 24 '25 18:10

Brian