赞
踩
local 对象:在Flask中,类似于request
对象,其实是绑定到了一个werkzeug.local.Local
对象上。
这样,即使是同一个对象,那么在多个线程中都是隔离的。类似的对象还有
from werkzeug.local import Local
# flask = werkzeug + sqlalchemy + jinja2
ThreadLocal变量:Python提供了ThreadLocal 变量,它本身是一个全局变量,但是每个线程却可以利用它来保存属于自己的私有数据,这些私有数据对其他线程也是不可见的。
总结:只要满足绑定到"local"或"Local"对象上的属性,在每个线程中都是隔离的,那么他就叫做ThreadLocal
对象,也叫’ThreadLocal’变量。
代码演示:
from threading import Thread,local
local =local()
local.request = '具体用户的请求对象'
class MyThread(Thread):
def run(self):
local.request = 'haha'
print('子线程:',local.request)
mythread = MyThread()
mythread.start()
mythread.join()
print('主线程:',local.request)
from werkzeug.local import Local
local = Local()
local.request = '具体用户的请求对象'
class MyThread(Thread):
def run(self):
local.request = 'tantan'
print('子线程:',local.request)
mythread = MyThread()
mythread.start()
mythread.join()
print('主线程:',local.request)
app上下文,也叫应用上下文。
LocalStack
的栈中。和应用app相关的操作就必须要用到应用上下文,比如通过 current_app
获取当前的这个 app
名字。注意 01:
在视图函数中,不用担心应用上下文的问题。因为视图函数要执行,那么肯定是通过访问url的方式执行的,
那么这种情况下,Flask底层就已经自动的帮我们把应用上下文都推入到了相应的栈中。
注意 02:
如果想要在视图函数外面执行相关的操作,比如获取当前的app名称,那么就必须要手动推入应用上下文:
第一种方式:便于理解的写法
from flask import Flask,current_app app = Flask(__name__) # app上下文 app_context = app.app_context() app_context.push() print(current_app.name) @app.route('/') def hello_world(): print(current_app.name) # 获取应用的名称 return 'Hello World!' if __name__ == '__main__': app.run(debug=True)
with
语句【推荐】from flask import Flask,current_app app = Flask(__name__) # app上下文 # 换一种写法 with app.app_context(): print(current_app.name) @app.route('/') def hello_world(): print(current_app.name) # 获取应用的名称 return 'Hello World!' if __name__ == '__main__': app.run(debug=True)
LocalStack
的栈中。url_for
反转视图函数。注意01:
在视图函数中,不用担心请求上下文的问题。
因为视图函数要执行,那么肯定是通过访问url的方式执行的,那么这种情况下,Flask底层就已经自动的帮我们把应用上下文和请求上下文都推入到了相应的栈中。
注意02:
如果想要在视图函数外面执行相关的操作,比如反转url,那么就必须要手动推入请求上下文:
from flask import Flask, url_for app = Flask(__name__) # 请求上下文 @app.route('/') def hello_world(): #和请求相关的操作就必须用到请求上下文,比如使用`url_for`反转视图函数。构建一个url=/mylist/ print(url_for('mylist')) return 'Hello World!' @app.route('/mylist/') def mylist(): return '我的列表' # 如果想要在视图函数外面执行相关的操作,比如反转url,那么就必须要手动推入请求上下文: # print(url_for('mylist')) # RuntimeError: Attempted to generate a URL without the application context being pushed. # This has to be executed when application context is available. # with app.app_context(): # print(url_for('mylist')) # 报错 # RuntimeError: Application was not able to create a URL adapter for request independent URL generation. # You might be able to fix this by setting the SERVER_NAME config variable. # 查看源代码 url_for() with app.test_request_context(): # 底层: # 推入请求上下文到栈中,会首先判断有没有应用上下文, # 如果没有那么就会先推入应用上下文到栈中, # 然后再推入请求上下文到栈中 print(url_for('mylist')) if __name__ == '__main__': app.run(debug=True)
总结:为什么上下文需要放在栈中?
应用上下文:Flask底层是基于werkzeug,werkzeug是可以包含多个app的,所以这时候用一个栈来保存。
如果你在使用app1,那么app1应该是要在栈的顶部,如果用完了app1,那么app1应该从栈中删除。方便其他代码使用下面的app。
如果在写测试代码,或者离线脚本的时候,我们有时候可能需要创建多个请求上下文,这时候就需要存放到一个栈中了。使用哪个请求上下文的时候,就把对应的请求上下文放到栈的顶部,用完了就要把这个请求上下文从栈中移除掉。
保存为全局对象g对象的好处:
g对象使用场景:有一个工具类 utils.py 和 用户办理业务
【30_g_object_demo.py】
from flask import Flask,g,request from utils import funa,funb,func app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World!' # g对象使用场景:有一个工具类utils.py 和 用户办理业务 # @app.route("/profile/") # def my_profile(): # #从url中取参 # uname = request.args.get('uname') # # #调用功能函数办理业务 # funa(uname) # funb(uname) # func(uname) # # #每次都得传参 麻烦,引入g对象进行优化 # return "办理业务成功" # Flask_线程隔离的g对象使用详解 @app.route("/profile/") def my_profile(): #从url中取参 uname = request.args.get('uname') # 调用功能函数办理业务 # funa(uname) # funb(uname) # func(uname) #每次都得传参 麻烦,引入g对象进行优化 g.uname = uname funa() funb() func() return "办理业务成功" if __name__ == '__main__': app.run(debug=True)
【utils.py】
# 工具类 # def funa(uname): # print('funa %s' % uname) # # def funb(uname): # print('funb %s' % uname) # # def func(uname): # print('func %s' % uname) from flask import g def funa(): print('funa %s' % g.uname) def funb(): print('funb %s' % g.uname) def func(): print('func %s' % g.uname)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。