Flask中本地代理的使用

1|0本地代理


当请求到来时应用上下文和程序上下文被推入本地栈中,全局变量current_app,request,g,session都可以使用了。以current_app为例,current_app代表的是app这个程序实例,但和app并不是同一个类型。current_app和app都有同样的功能,但是current_app和app不是一个对象。

from flask import Flask, current_app app = Flask(__name__) @app.route('/') def hello_world(): print(f"{app} {type(app)}") print(f"{current_app} {type(current_app)}") return f"Hello world!" if __name__ == '__main__': app.run()
<Flask 'flask_demo'> <class 'flask.app.Flask'> <Flask 'flask_demo'> <class 'werkzeug.local.LocalProxy'>

可以看出app和current_app都是flask的实例,但是两者的类型是不一样的。app就是flask实例本尊,是真的美猴王,而current_app是werkzeug模块里的本地代理对象,一个假美猴王。

为了探究这个问题,可以从current_app的定义入手。
从current_app的定义来就能知道,不光是current_app是本地代理对象,request,session,g等都是代理对象。

def _lookup_req_object(name): top = _request_ctx_stack.top if top is None: raise RuntimeError(_request_ctx_err_msg) return getattr(top, name) def _lookup_app_object(name): top = _app_ctx_stack.top if top is None: raise RuntimeError(_app_ctx_err_msg) return getattr(top, name) def _find_app(): top = _app_ctx_stack.top if top is None: raise RuntimeError(_app_ctx_err_msg) return top.app _request_ctx_stack = LocalStack() _app_ctx_stack = LocalStack() current_app = LocalProxy(_find_app) request = LocalProxy(partial(_lookup_req_object, 'request')) session = LocalProxy(partial(_lookup_req_object, 'session')) g = LocalProxy(partial(_lookup_app_object, 'g'))

这里出现一个重要的概念本地代理,首先要搞明白什么是本地代理。

2|0LocalProxy 介绍


LocalProxy 中文本地代理,和前面介绍的本地线程和本地栈类似,都可以根据线程隔离变量,同时还有代理的功能。
代理在生活中及其常见,比如现在的美团跑腿,你上班时间时间需要送一份文件给朋友,自己又抽不开身,这时可以预约一个全城送,付钱让他给你送文件。这个代送小哥就是一个代理。

广义的代理就是访问对象无法直接访问目标对象,代理对象作为中介,将访问传递给目标对象。

不使用代理
localstack获取栈顶元素的方法就是通过一个函数返回localstack的top。current_app的定义中的_find_app就是获取栈顶元素的函数。首先模拟不使用代理的方法来获取栈顶元素。

from werkzeug.local import LocalStack, LocalProxy test_stack = LocalStack() test_stack.push({'abc': '123'}) def get_stack_top(): return test_stack.top item = get_stack_top() print(item) # 有新的元素入栈 test_stack.push({'abc': '1234'}) print(item)
{'abc': '123'} {'abc': '123'}

当调用get_stack_top时,获取的最新的栈顶元素item。有元素入栈之后,item就不再是栈顶元素了。根据flask中current_app的使用,无论何时current_app, 都是获取栈顶元素。所以需要再次调用函数去获取栈顶元素。

使用本地代理
使用本地代理就不需要每次调用函数去获取栈顶元素,可以做到在app1入栈时current_app栈顶是app1,app2入栈时栈顶是app2。

from werkzeug.local import LocalStack, LocalProxy test_stack = LocalStack() test_stack.push({'abc': '123'}) def get_stack_top(): return test_stack.top item = LocalProxy(get_stack_top) print(item) # 当栈发生变化时,再次使用使用代理对象,仍然可以获取到栈顶元素。 # 原理时每次访问item时,localproxy都会调用get_stack_top去获取栈顶 test_stack.push({'abc': '1234'}) print(item)
{'abc': '123'} {'abc': '1234'}

将获取栈顶元素的函数传入LocalProxy,然后访问LocalProxy实例item,每次都能获取栈顶元素,而不需要再次调用获取栈顶的函数get_stack_top。原理在于每次去访问item时,本地代理都是调用get_stack_top函数去获取栈顶,相当于帮我们去调用了函数。

3|0小结


本地代理的使用是传入要获取栈顶的函数,当每次访问本地代理对象时,本地代理调用函数获取最新栈顶,减少了业务中调用函数的过程,是获取栈顶元素的一种优雅方法。

上下文中的4种全局变量都是本地代理对象,任何时候访问这4中变量时,本地代理能返回最新的栈顶元素。

4|0系列总结


写到这里就将Flask中最核心的请求处理介绍完了。这个系列由浅入深,分别介绍了:

  1. 最简单Flask程序
  2. Flask依赖的核心模块werkzeug
  3. Flask请求数据的优雅传递
  4. Flask中本地栈的使用
  5. Flask中本地代理的使用

可以这个主题是Flask最值得探讨赏析的技术之一,通过这个系列我学习到一些全新的知识,如全局变量的线程隔离,代理模式的优雅,Flask请求和非请求场景下业务的统一等。能够弄明白这些知识虽然也花费了很多时间但是很值得。所谓山有路勤为径,学海无涯苦作舟。


__EOF__

本文作者goldsunshine
本文链接https://www.cnblogs.com/goldsunshine/p/15890866.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   金色旭光  阅读(711)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示