【问题标题】: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>'

是否有解决此问题的方法?非常感谢任何帮助!

【问题讨论】:

    标签: python flask decorator python-decorators


    【解决方案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参数在哪里?即homeroute_1route_2
      猜你喜欢
      • 2021-05-15
      • 1970-01-01
      • 2020-07-08
      • 2013-07-05
      • 1970-01-01
      • 1970-01-01
      • 2021-08-20
      • 1970-01-01
      • 2015-04-18
      相关资源
      最近更新 更多