使用定义为实例变量的装饰器函数
Posted
技术标签:
【中文标题】使用定义为实例变量的装饰器函数【英文标题】:Using a decorator function defined as an instance variable 【发布时间】:2017-05-07 16:01:51 【问题描述】:(虽然这个问题是专门针对Flask的,但可以根据题目概括一下)
我正在尝试在类中使用 Flask 的 app.route()
装饰器。但是,Flask 应用程序被初始化为实例变量,即 self.server
设置为应用程序。这意味着我不能使用装饰器,因为 self
在装饰方法之外是未定义的。我希望能够做到以下几点:
class MyClass:
def __init__(self):
self.server = Flask(__name__)
@self.server.route('/')
def home():
return '<h1>Success</h1>'
是否有解决此问题的方法?非常感谢任何帮助!
【问题讨论】:
【参考方案1】:您可以在__init__
方法的上下文中定义函数。然后,为了使函数能够正常调用,将home
成员设置为等于它。
class MyClass:
def __init__(self):
self.server = Flask(__name__)
# This is indented at __init__'s level, so a new instance of the function
# is defined every time __init__ runs. That means a new instance
# is defined for each instance of the class, and so it can be wrapped with
# the instance's "self" value.
@self.server.route('/')
def home_func():
return '<h1>Success</h1>'
# Then, you make it an object member manually:
self.home = home_func
【讨论】:
我认为这不是一个前瞻性的解决方案,因为您最终会得到一个包含所有路由定义及其各自功能的大量__init__()
方法。最好使用add_url_rule()
function,正如我自己(和@rumdrums)对这个问题的回答中所解释的那样。
对于 Flask,这可能会更好。然而,即使对于不使用 Flask 的人来说,这也是一个很好的问题。此外,以这种方式定义函数只需要比add_url_rule
多一行,所以我认为“大量的__init__()
方法”并不特别重要。
很公平!纯粹作为一项学术练习,也可以使用route
装饰器对__init__
方法中的MyClass
类的方法进行猴子补丁,方法是执行self.home = self.server.route('/')(self.home)
之类的操作。这是在一些可能遇到的棘手场景中装饰函数/方法的便捷方式,而不仅仅是 Flask 和路由。【参考方案2】:
我不确定您的整体用例是什么,但最好不要将应用程序对象嵌入到类中,而是使用 Flask 的 Pluggable Views 模块。这将允许您将视图清晰地定义为从 flask.views.View 继承的类。示例:
import flask
import flask.views
class MyClass(flask.views.View):
def dispatch_request(self):
return '<h1>Success</h1>'
app.add_url_rule('/test', view_func=MyClass.as_view('home'))
对于这个小例子来说,这肯定是更多的代码,但这让您可以更灵活地使用自己的路由定义其他类或函数,并可能考虑使用 MethodViews,它为定义多个 HTTP 方法并将它们关联起来提供了一个良好的结构一个班级。
【讨论】:
【参考方案3】:您应该使用self.server
对象的add_url_rule
method,而不是使用route()
装饰器,如下所示:
class MyClass:
def __init__(self):
self.server = Flask(__name__)
self.server.add_url_rule('/', 'home', self.home)
self.server.add_url_rule('/route-1', 'route-1', self.route_1)
self.server.add_url_rule('/route-2', 'route-2', self.route_2)
def home():
return '<h1>Success</h1>'
def route_1():
...
def route_2():
...
此模式允许您将路由处理程序定义为类上的方法,并且更易于阅读,因为您可以在一个块中查看所有 URL 规则。
【讨论】:
每个方法的self参数在哪里?即home
、route_1
和route_2
。以上是关于使用定义为实例变量的装饰器函数的主要内容,如果未能解决你的问题,请参考以下文章