【问题标题】:Object Oriented Python with Flask Server?面向对象的 Python 与 Flask 服务器?
【发布时间】:2014-09-19 02:00:47
【问题描述】:

我正在使用 Flask 将一些数据处理代码公开为 Web 服务。 我想要一些我的 Flask 函数可以访问的类变量。

让我带你了解我被困的地方:

from flask import Flask
app = Flask(__name__)

class MyServer:
  def __init__(self):
    globalData = json.load(filename)

  @app.route('/getSomeData')
  def getSomeData():
    return random.choice(globalData) #select some random data to return

if __name__ == "__main__":
  app.run(host='0.0.0.0')

当我在 Flask 之外运行 getSomeData() 时,它运行良好。但是,当我用 Flask 运行它时,我得到了500 internal server error。这里没有魔法,Flask 也不知道它应该初始化一个MyServer 对象。如何将 MyServer 的实例提供给 app.run() 命令?

我可以认输并将globalData 放入数据库中。但是,还有别的办法吗?

【问题讨论】:

    标签: python flask


    【解决方案1】:

    您可以在端点范围之外创建MyServer 的实例并访问其属性。这对我有用:

    class MyServer:
        def __init__(self):
            self.globalData = "hello"
    
    from flask import Flask
    app = Flask(__name__)
    
    my_server = MyServer()
    
    @app.route("/getSomeData")
    def getSomeData():
        return my_server.globalData
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0")
    

    【讨论】:

    • 这是一个不错的选择,但您仍然无法编写端到端测试和模拟依赖项(如网络或文件系统 IO),因为您的依赖项没有注入。你可以做一些像unittest.mock.patch 这样的hacky,但是你必须注意构建你的真实服务器,就像你构建你的测试服务器一样(当然,除了模拟之外)。这基本上是单例反模式
    【解决方案2】:

    我知道这是一个迟到的回复,但我在面临类似问题时遇到了这个问题。我发现flask-classful 真的很好。 您从 FlaskView 继承您的类,并将 Flask 应用程序注册到您的 MyServer 类

    http://flask-classful.teracy.org/#

    在这种情况下,使用 flask-classful,您的代码将如下所示:

    from flask import Flask
    from flask_classful import FlaskView, route
    
    app = Flask(__name__)
    
    class MyServer(FlaskView):
      def __init__(self):
        globalData = json.load(filename)
    
      @route('/getSomeData')
      def getSomeData():
        return random.choice(globalData) #select some random data to return
    
    
    MyServer.register(app, base_route="/")
    
    
    if __name__ == "__main__":
      app.run(host='0.0.0.0')
    

    【讨论】:

    【解决方案3】:

    耦合最少的解决方案是在运行时(而不是在加载时)应用路由:

    def init_app(flask_app, database_interface, filesystem_interface):
        server = MyServer(database_interface, filesystem_interface)
        flask_app.route('get_data', methods=['GET'])(server.get_data)
    

    这是非常可测试的——只需在您的测试代码中调用 init_app() 并使用模拟/伪造的依赖项(database_interface 和 filesystem_interface)和一个已配置用于测试的烧瓶应用程序(app.config["TESTING"]=True 或类似的东西那)并且您已经准备好编写涵盖整个应用程序(包括烧瓶路由)的测试。

    唯一的缺点是这不是很“Flasky”(或者有人告诉我); Flask 习惯用法是使用@app.route(),它在加载时应用,并且必须紧密耦合,因为依赖项被硬编码到实现中,而不是注入到某些构造函数或工厂方法中(因此测试起来很复杂)。

    【讨论】:

    • Flask将server.get_data传入MyServer的实例,但是请求数据在哪里呢?
    【解决方案4】:

    有点晚了,但这是我用来在初始化时注册路由的快速实现

    from flask import Flask,request,render_template
    from functools import partial
    
    
    registered_routes = {}
    def register_route(route=None):
        #simple decorator for class based views
        def inner(fn):
            registered_routes[route] = fn
            return fn
        return inner
    
    class MyServer(Flask):
        def __init__(self,*args,**kwargs):
            if not args:
                kwargs.setdefault('import_name',__name__)
            Flask.__init__(self,*args ,**kwargs)
            # register the routes from the decorator
            for route,fn in registered_routes.items():
                partial_fn = partial(fn,self)
                partial_fn.__name__ = fn.__name__
                self.route(route)(partial_fn)
    
    
        @register_route("/")
        def index(self):
            return render_template("my_template.html")
    
    if __name__ == "__main__":
        MyServer(template_folder=os.path.dirname(__file__)).run(debug=True)
    

    【讨论】:

      【解决方案5】:

      如果您希望将 MyServer 类作为资源使用
      相信flask_restful可以帮到你:

      from flask import Flask
      from flask_restful import Resource, Api
      import json
      import numpy as np
      
      app = Flask(__name__)
      api = Api(app)
      
      class MyServer(Resource):
          def __init__(self):
              self.globalData = json.load(filename)
      
          def get(self):
              return np.random.choice(self.globalData)
      
      api.add_resource(MyServer, '/')
      
      if __name__ == '__main__':
          app.run()
      

      【讨论】:

        【解决方案6】:

        以下代码是使用 Flask 进行 OOP 的简单解决方案:

        from flask import Flask, request
        
        
        class Server:
            def __init__(self, name):
                self.app = Flask(name)
        
                @self.app.route('/')
                def __index():
                    return self.index()
        
                @self.app.route('/hello')
                def __hello():
                    return self.hello()
        
                @self.app.route('/user_agent')
                def __user_agent():
                    return self.user_agent()
        
                @self.app.route('/factorial/<n>', methods=['GET'])
                def __factorial(n):
                    return self.factorial(n)
        
            def index(self):
                return 'Index Page'
        
            def hello(self):
                return 'Hello, World'
        
            def user_agent(self):
                return request.headers.get('User-Agent')
        
            def factorial(self, n):
                n = int(n)
                fact = 1
                for num in range(2, n + 1):
                    fact = fact * num
                return str(fact)
        
            def run(self, host, port):
                self.app.run(host=host, port=port)
        
        
        def main():
            server = Server(__name__)
            server.run(host='0.0.0.0', port=5000)
        
        
        if __name__ == '__main__':
            main()
        

        要测试代码,请浏览以下网址:

        • http://localhost:5000/
        • http://localhost:5000/hello
        • http://localhost:5000/user_agent
        • http://localhost:5000/factorial/10

        【讨论】:

          猜你喜欢
          • 2019-10-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-19
          • 1970-01-01
          • 1970-01-01
          • 2011-08-09
          相关资源
          最近更新 更多