问题
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.
回答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 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.
回答2:
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'
回答3:
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 :)
来源:https://stackoverflow.com/questions/46897417/convert-a-bound-method-in-python-to-a-function-and-reduce-arg-count