Search code examples
pythonfunctionmethodsflask

Convert a bound method in python to a function (and reduce arg count)


I am adding a URL handler to a Flask application using add_url_rule. It requires a function as a handler (not a method). However, for proper encapsulation, my intended function is a bound method that uses the self variable. Is there any way I can somehow make Flask see my function: def action(self, param) as def action(param) ?

class A():
    def __init__(self):
        self._localvar = 5
        self._flask = Flask("testapp")

    def add_rules(self):
        self._flask.add_url_rule("/","root",????)

    def action(self, value):
        print("The value is {}".format(self._localvar))

    def run(self):
        self._flask.run()

app = A()
app.add_rules()
app.run()

what I want to do is replace ???? with app.action, a bound method. However, add_url_rule expects a function. I tried app.action.__func__ and app.action.im_func which are function pointers. However, the function signature is still going to require self and will give me a runtime error.

My current solution is to have some loose functions in my module and have app just use them directly, but it just seems that there has to be a cleaner way since the handlers are really tightly coupled to the app object and I don't want them floating around outside of it.


Solution

  • I Think I finally found a way to do this (i.e. keep the action method bound inside my class and have a function-like reference to it when needed). I used a function inside a method:

    class A():
        def __init__(self):
            self._localvar = 5
            self._flask = Flask("testapp")
    
        def add_rules(self):
            self._flask.add_url_rule("/","root",self.action_as_func())
    
        def action(self, value):
            print("The value is {}".format(self._localvar))
    
        def action_as_func(self):
            def inner_action(value):
                self.action(value)
            return inner_action
    
        def run(self):
            self._flask.run()
    
    app = A()
    app.add_rules()
    app.run()
    

    Any comments on whether there is something wrong with this ? The function can access self. Kinda sneaky :)