Python Flask上下文管理机制实例解析

前言

上下文这个概念多见于文章中,是一句话中的语境,也就是语言环境。一句莫名其妙的话出现会让人不理解什么意思,如果有语言环境的说明,则会更好,这就是语境对语意的影响。

上下文是一种属性的有序序列,为驻留在环境内的对象定义环境。在对象的激活过程中创建上下文,对象被配置为要求某些自动服务,如同步、事务、实时激活、安全性等等。

如在计算机中,相对于进程而言,上下文就是进程执行时的环境。具体来说就是各个变量和数据,包括所有的寄存器变量、进程打开的文件、内存信息等。可以理解上下文是环境的一个快照,是一个用来保存状态的对象。在程序中我们所写的函数大都不是单独完整的,在使用一个函数完成自身功能的时候,很可能需要同其他的部分进行交互,需要其他外部环境变量的支持,上下文就是给外部环境的变量赋值,使函数能正确运行。

请求上下文

关于WSGI

WSGI(全称Web Server Gateway Interface),是为 Python 语言定义的Web服务器和Web应用程序之间的一种简单而通用的接口,它封装了接受HTTP请求、解析HTTP请求、发送HTTP,响应等等的这些底层的代码和操作,使开发者可以高效的编写Web应用。

Flask提供了两种上下文,一种是应用上下文(Application Context),一种是请求上下文(Request Context)。

  • RequestContext 请求上下文
  • Request 请求的对象,封装了Http请求(environ)的内容
  • Session 根据请求中的cookie,重新载入该访问者相关的会话信息。
  • AppContext 程序上下文
  • g 处理请求时用作临时存储的对象。每次请求都会重设这个变量
  • current_app 当前激活程序的程序实例

参见Flask上下文官方文档 请求上下文应用上下文.

  1. application 指的就是当你调用app = Flask(__name__)创建的这个对象app;

  2.request 指的是每次http请求发生时,WSGI server(比如gunicorn)调Flask.call()之后,在Flask对象内部创建的Request对象;

  3.application 表示用于响应WSGI请求的应用本身,request 表示每次http请求;

  4.application的生命周期大于request,一个application存活期间,可能发生多次http请求,所以,也就会有多个request

生命周期

  • current_app的生命周期最长,只要当前程序实例还在运行,都不会失效。
  • Request和g的生命周期为一次请求期间,当请求处理完成后,生命周期也就完结了
  • Session就是传统意义上的session了。只要它还未失效(用户未关闭浏览器、没有超过设定的失效时间),那么不同的请求会共用同样的session。

Flask处理流程

local线程隔离对象

不用local对象的情况

from threading import Thread

request = '123'

class MyThread(Thread):
  def run(self):
    global request
    request = 'abc'
    print('子线程',request)  #子线程 abc

mythread = MyThread()
mythread.start()
mythread.join()

print('主线程',request)     #主线程 abc

如果用local对象,在每个线程中都是隔离的

from threading import Thread
from werkzeug.local import Local

locals = Local()
locals.request = '123'

class MyThread(Thread):
  def run(self):
    locals.request = 'abc'
    print('子线程',locals.request)  #子线程 abc

mythread = MyThread()
mythread.start()
mythread.join()

print('主线程',locals.request)     #主线程 123

app上下文和request上下文

应用上下文和请求上下文都是存放在一个‘LocalStack'的栈中,和应用app相关的操作就必须要用到应用上下文,比如通过current_app获取当前的这个app的名字。和请求相关的操作就必须用到请求上下文,比如使用url_for反转视图函数。

在视图函数中,不用担心上下文的问题,因为视图函数要执行,name肯定是通过访问url的方式执行的,name这种情况下,Flask底层就已经自动的帮我们把请求上年文和应用上下文都推入到了相应的栈中。如果想要在视图函数外面执行相关的操作,name就必须要手动推入相关的上下文手动推入请求上下文:推入请求上下文到栈中,会首先判断有没有应用上下文,如果没有那么就会先推入应用上下文到栈中,然后再推入请求上下文到栈中。

app上下文

from flask import Flask,current_app

app = Flask(__name__)

#如果在视图函数外部访问,则必须手动推入一个app上下文到app上下文栈中
#第一种方法
# app_context = app.app_context()
# app_context.push()
# print(current_app.name)

#第二种方法
with app.app_context():
  print(current_app.name)   #context_demo

@app.route('/')
def index():
  # 在视图函数内部可以直接访问current_app.name
  print(current_app.name)  #context_demo
  return 'Hello World!'

if __name__ == '__main__':
  app.run(debug=True)

request请求上下文

from flask import Flask,current_app,url_for

app = Flask(__name__)

#应用上下文
#如果在视图函数外部访问,则必须手动推入一个app上下文到app上下文栈中
with app.app_context():
  print(current_app.name)   #context_demo

@app.route('/')
def index():
  # 在视图函数内部可以直接访问current_app.name
  print(current_app.name)  #context_demo
  return 'Hello World!'

@app.route('/list/')
def my_list():
  return 'my_list'

# 请求上下文
with app.test_request_context():
  # 手动推入一个请求上下文到请求上下文栈中
  # 如果当前应用上下文栈中没有应用上下文
  # 那么会首先推入一个应用上下文到栈中
  print(url_for('my_list'))

if __name__ == '__main__':
  app.run(debug=True)

为什么上下文需要放在栈中?

1.应用上下文:

Flask底层是基于werkzeug,werkzeug是可以包含多个app的,所以这时候用一个栈来保存,如果你在使用app1,那么app1应该是要在栈的顶部,如果用完了app1那么app应该从栈中删除,方便其他代码使用下面的app。

2.应用上下文:

如果在写测试代码,或者离线脚本的时候,我们有时候可能需要创建多个请求上下文,这时候就需要存放到一个栈中了。使用哪个请求上下文的时候,就把对应的请求上下文放到栈的顶部,用完了就要把这个请求上下文从栈中移除掉。

线程隔离的g对象

g对象是在整个Flask应用运行期间都是可以使用的,并且它也是跟request一样是线程隔离的。这个对象是专门用来存储开发者自定义的一些数据,方便在整个Flask程序中都可以使用。一般使用就是,将一些经常会用到的数据绑定到上面,以后就直接从g上面取就可以了,而不是通过传参的形式,这样更加方便。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • python flask中动态URL规则详解

    URL是可以添加变量部分的, 把类似的部分抽象出来, 比如: @app.route('/example/1/') @app.route('/example/2/') @app.route('/example/3/') def example(id): return 'example:{ }'.format(id) 可以抽象为: @app.route('/example/<id>/') def wxample(id): return 'example:{ }'.format(id) 尖括号中的内

  • 在flask中使用python-dotenv+flask-cli自定义命令(推荐)

    最近在重构 flask 项目的时候发现项目的环境变量异常的混乱,非常不便于管理.而且,更重要的事情是我需要通过自定义命令来运行 devlopment 和 production 两种项目环境. 自定义命令工具--flask-cli 在Flask 1.0+ 中已经支持了flask-cli,在翻阅了flask-cli文档之后,发现文档中提供的自定义命令的方法约束还是有点多,而且介绍的也不是特别详细.后来,通过查看flask-cli的源码发现flask-cli是基于Click开发的. Click is

  • python 实现Flask中返回图片流给前端展示

    场景需求:需要在Flask服务器的本地找一张图片返回给前端展示出来. 问题疑点:通常前端的<img>标签只会接受url的形式来展示图片,没试过在返回服务器本地的一张图片给前端. 因此写个记录一下这个看起来有点奇葩的场景(通常个人博客,个人网站没有钱用第三方的服务都会采用存储在服务器本地的方法啦.) 项目目录: dyy_project | |----static (新建flask项目时自动建的,没有任何文件) |----templates |-----index.html (前端页面) |---

  • python 解决flask 图片在线浏览或者直接下载的问题

    目前是把图片存在mongodb数据库,实现一个方法,比如 访问 /get_pic/ID 能实现图片在浏览器打开,添加了一个状态,比如?filename=1.png,实现图片直接下载, 需要在读取图片函数中,给response 加上headers: 在 flask 中 response=make_response(f.read()) 需要下载就添加以下headers 当filename为中文时会报asicc编解码错误, 此时,import urllib (py3) filename=urllib.

  • Python中Flask-RESTful编写API接口(小白入门)

    1.API接口:hello world 案例 from flask import Flask from flask_restful import Api, Resource app = Flask(__name__) api = Api(app) class HelloWorld(Resource): def get(self): return {'hello': 'world'} api.add_resource(HelloWorld, '/') if __name__ == '__main_

  • Python如何通过Flask-Mail发送电子邮件

    这篇文章主要介绍了Python如何通过Flask-Mail发送电子邮件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 采用Flask-Mail模块发送电子邮件 代码如下 ##python程序 命名为hello.py import os from flask import Flask from flask_mail import Mail from flask_script import Manager app = Flask(__name__)

  • Python-Flask:动态创建表的示例详解

    今天小编从项目的实际出发,由于项目某一个表的数据达到好几十万条,此时数据的增删查改会很慢:为了增加提高访问的速度,我们引入动态创建表. 代码如下: from app_factory import app from sqlalchemy import Column, String, Integer class ProjectModel(app.db.model, app.db.Mixin): tablename = 'Project_' ID = Column(String(50), name='

  • python 解决flask uwsgi 获取不到全局变量的问题

    问题 在写flask,使用uwsgi启动的时候,涉及到多request线程访问同一个全局变量,发现不能获取到全局变量的值的修改,这在flask独立启动的时候是没有问题的. 伪代码 全局变量 @app.route('/request1/') def 函数1 修改全局变量 @app.route('/request2/') def 函数2 获取全局变量 严重怀疑是uwsgi的线程机制的问题,因为uwsgi是可以指定子进程的数目的,然而我设置子进程数目为1,之后,在处理函数1的时候是不能同时处理函数2的

  • Python Flask上下文管理机制实例解析

    前言 上下文这个概念多见于文章中,是一句话中的语境,也就是语言环境.一句莫名其妙的话出现会让人不理解什么意思,如果有语言环境的说明,则会更好,这就是语境对语意的影响. 上下文是一种属性的有序序列,为驻留在环境内的对象定义环境.在对象的激活过程中创建上下文,对象被配置为要求某些自动服务,如同步.事务.实时激活.安全性等等. 如在计算机中,相对于进程而言,上下文就是进程执行时的环境.具体来说就是各个变量和数据,包括所有的寄存器变量.进程打开的文件.内存信息等.可以理解上下文是环境的一个快照,是一个用

  • python并发编程之线程实例解析

    常用用法 t.is_alive() Python中线程会在一个单独的系统级别线程中执行(比如一个POSIX线程或者一个Windows线程) 这些线程将由操作系统来全权管理.线程一旦启动,将独立执行直到目标函数返回.可以通过查询 一个线程对象的状态,看它是否还在执行t.is_alive() t.join() 可以把一个线程加入到当前线程,并等待它终止 Python解释器在所有线程都终止后才继续执行代码剩余的部分 daemon 对于需要长时间运行的线程或者需要一直运行的后台任务,可以用后台线程(也称

  • ArrayList的自动扩充机制实例解析

    用一道选择题作为本文的开始吧! ArrayList list = new ArrayList(20);中的list扩充几次 A.0 B.1 C.2 D.3 答案:A 1.ArrayList的默认初始容量为10,当然也可以自定义指定初始容量,随着动态的向其中添加元素,其容量可能会动态的增加,那么扩容的公式为: 新容量 = 旧容量/2 + 旧容量 比如:初始容量为4,其容量的每次扩充后的新容量为:4->6->9->13->19->- 即每次扩充至原有基础的1.5倍 ArrayLi

  • python re模块findall()函数实例解析

    本文研究的是re模块findall()函数的相关内容,首先看看实例代码: >>> import re >>> s = "adfad asdfasdf asdfas asdfawef asd adsfas " >>> reObj1 = re.compile('((\w+)\s+\w+)') >>> reObj1.findall(s) [('adfad asdfasdf', 'adfad'), ('asdfas asd

  • Python中实现switch功能实例解析

    前言 今天在学习python的过程中,发现python没有switch这个语法.于是就想在python中如何才能实现这个功能呢? 正文 本文中我们对switch的使用模拟为正常的数据库的增删改查操作的对应,如'select 对应'select action'等. 1.简单的if-else 正如我们所知,python中有if语句,而且当时学习C的时候,学到if-else时引出的的替代品就是switch,两者可以完美的互相替代,需要注意的是在python中else if简化成了elif.如下所示:

  • python使用锁访问共享变量实例解析

    本文研究的主要是python使用锁访问共享变量,具体介绍和实现如下. python 做多线程编程时,多个线程若同时访问某个变量,可能会对变量数据造成破坏,pyhon中的threading模块提供了lock对象,lock中的acquire方法用于获取一个锁,而release用于释放一个锁.当一个线程取得锁时,它变获得了共享变量的访问权,此时进入阻塞状态,若其它线程申请访问这个变量,则必须等到这个线程调用release方法释放这个锁.下面是python中使用锁的实例: #!/usr/bin/env

  • Python使用Pandas读写Excel实例解析

    这篇文章主要介绍了Python使用Pandas读写Excel实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Pandas是python的一个数据分析包,纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具. Pandas提供了大量能使我们快速便捷地处理数据的函数和方法. Pandas官方文档:https://pandas.pydata.org/pandas-docs/stable/ Pandas中文文档:https:/

  • Python zip函数打包元素实例解析

    这篇文章主要介绍了Python zip函数打包元素实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 介绍 zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表. ps. 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表. 例子 a = [1,2,3] b = [4,5,6] c = [4,5,6,7,8] zipped = zi

  • Python assert关键字原理及实例解析

    这篇文章主要介绍了Python assert关键字原理及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Python assert(断言)用于判断一个表达式,在表达式条件为 False 的时候触发异常. 断言可以在条件不满足程序运行的情况下直接返回错误,而不必等待程序运行后出现崩溃的情况. 语法格式: assert expression 等价于: if not expression: raise AssertionError asser

  • Python列表切片常用操作实例解析

    这篇文章主要介绍了Python列表切片常用操作实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 最近在爬一个网站的文档的时候,老师要求把一段文字切割开来,根据中间的文本分成两段 故学习了一段时间的切片操作,现把学习成果po上来与大家分享 1.何为切片? 列表的切片就是处理列表中的部分元素,是把整个列表切开的方法. 切片可以说是整个列表中的重点内容,相信你在以后的Python项目中会经常使用到. 它的语法是: 2.简单介绍切片的几个常见操作

随机推荐