1

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.

9
  • So what is self going to reference then? If you have a single, global instance, use a = A() and register a.action. Commented Oct 23, 2017 at 19:52
  • Note that route handlers are global anyway, so why the class encapsulation? You only register one for each path. Commented Oct 23, 2017 at 19:53
  • 1
    What happens if you pass it app.action? Commented Oct 23, 2017 at 20:06
  • 1
    What I want to know is whether there is a python way to somehow "cast" a def action(value) to the def action(self, value) and somehow smartly replace the self references with the address of my self such that this method becomes compatible with the register type Commented Oct 23, 2017 at 20:15
  • 1
    You've defined an A class, but you don't seem to have an instance of A anywhere. app is an instance of Flask, an entirely unrelated class. What A instance do you want to call the action method of? Commented Oct 23, 2017 at 20:16

4 Answers 4

4

This is an old question, but I thought it might be useful to know a possibly easier solution for someone (like me) visiting this page.

You can access the underlying function of a bound method as its __func__ attribute. Also, if you access it as an attribute of the class and not the instance, it will give you the function.

class C: def fn(self, param): return param instance = C() print(instance.fn("hello")) # 'hello' print(instance.fn.__func__(instance, "hello")) # 'hello' print(instance.fn.__func__(None, "hello")) # 'hello' print(C.fn(instance, "hello")) # 'hello' print(C.fn(None, "hello")) # 'hello' 
Sign up to request clarification or add additional context in comments.

Comments

2

What I want to know is whether there is a python way to somehow "cast" a def action(value) to the def action(self, value) [...]

And what if you do it the other way around? You define your actions as functions (or staticmethods if you want to keep them in the class A), and bind them to your instance only when you need them.

You could use the types module to bind a function to an instance.

import types class A(): def bind_action_func_to_instance(self, func, value): self.action_method = types.MethodType(func, self) @staticmethod def action_func(value): print('action with value: {}'.format(value)) def add_rules(): self._flask.add_url_rule("/","root", self.action_func) 

You could also implement a default action method and assign it to action_method in the __init__. It will then be reassigned when you call bind_action_func_to_instance.

I think you could also find useful this answer about the Strategy pattern.

1 Comment

But would this allow me to use the variable "self" inside the static method ? I am assuming not. Still, I up vote for use of types module
2

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 :)

Comments

0

Try passing lambda x:A.action(app,x) to add_url_rule.

2 Comments

Welcome to Stack Overflow! It's important to understand how this site is different from others. You posted this as an answer, but it might appear to ask a question. I would suggest an Edit to the post to rephrase this in the form of an answer/suggestion.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.