我一直在使用请求/应用程序上下文有一段时间,但并没有完全了解它的工作原理或设计原因。当涉及到请求或应用程序上下文时,“堆栈”的目的是什么?这是两个单独的堆栈,还是都是一个堆栈的一部分?是将请求上下文压入堆栈,还是堆栈本身?我是否可以在彼此之上推送/弹出多个上下文?如果是这样,我为什么要这样做?
抱歉所有问题,但是阅读了请求上下文和应用程序上下文文档后,我仍然感到困惑。
Multiple Apps
在你意识到Flask可以拥有多个应用程序之前,应用程序上下文(及其用途)确实令人困惑。想象一下你想让一个WSGI Python解释器运行多个Flask应用程序的情况。我们不是在这里谈论蓝图,而是在谈论完全不同的Flask应用程序。
你可以将其设置类似于“应用程序调度”示例中的Flask文档部分:
from werkzeug.wsgi import DispatcherMiddleware
from frontend_app import application as frontend
from backend_app import application as backend
application = DispatcherMiddleware(frontend, {
'/backend': backend
})
请注意,有两个完全不同的Flask应用程序被创建为“前端”和“后端”。换句话说,Flask(…)应用程序构造函数被调用了两次,创建了Flask应用程序的两个实例。
Contexts
当你使用Flask时,通常会最终使用全局变量来访问各种功能。例如,你可能有读取如下代码。
from flask import request
然后,在查看期间,你可能会request
用来访问当前请求的信息。显然,request
这不是正常的全局变量;实际上,它是上下文局部值。换句话说,幕后隐藏着一些魔术,上面写着“当我打电话时request.path,path
从requestCURRENT
请求的对象获取属性”。两个不同的请求将对产生不同的结果request.path
。
实际上,即使你使用多个线程运行Flask,Flask
也足够聪明,可以将请求对象隔离。这样,两个线程(每个线程处理一个不同的请求)就可以同时调用request.path
并获取各自请求的正确信息。
Putting it Together
因此,我们已经看到Flask可以在同一个解释器中处理多个应用程序,并且由于Flask允许你使用“上下文本地”全局变量的方式,因此必须有某种机制来确定“当前” 请求是什么(为了做)之类的事情request.path
。
将这些想法放在一起,Flask
必须具有某种方法来确定“当前”应用程序是什么也应该有意义!
你可能还具有类似于以下内容的代码:
from flask import url_for
像我们的request
示例一样,该url_for
函数的逻辑取决于当前环境。但是,在这种情况下,可以清楚地看到逻辑在很大程度上取决于哪个应用程序被视为“当前”应用程序。在上面显示的前端/后端示例中,“前端”和“后端”应用程序都可能具有“ /登录”路由,因此url_for('/login')
应返回不同的内容,具体取决于视图是否正在处理针对前端或后端应用程序的请求。
要回答你的问题…
当涉及到请求或应用程序上下文时,“堆栈”的目的是什么?
从请求上下文文档中:
由于请求上下文在内部作为堆栈维护,因此你可以多次推送和弹出。这对于实现内部重定向之类的操作非常方便。
换句话说,即使你通常在这些“当前”请求或“当前”应用程序堆栈中包含0或1个项目,也可能会有更多或更多的项目。
给出的示例是让你的请求返回“内部重定向”结果的地方。假设某个用户请求A,但你想返回到该用户B。在大多数情况下,你将向该用户发出重定向,并将该用户指向资源B,这意味着该用户将运行第二个请求以获取B。稍微不同的处理方式是进行内部重定向,这意味着在处理A时,Flask将向自身发出对资源B的新请求,并将第二个请求的结果用作用户原始请求的结果。
这是两个单独的堆栈,还是都是一个堆栈的一部分?
它们是两个单独的堆栈。但是,这是一个实现细节。更重要的是没有堆栈,而是可以随时获取“当前”应用程序或请求(堆栈顶部)的事实。
是将请求上下文压入堆栈,还是堆栈本身?
“请求上下文”是“请求上下文堆栈”的一项。与“应用程序上下文”和“应用程序上下文堆栈”类似。
我是否可以在彼此之上推送/弹出多个上下文?如果是这样,我为什么要这样做?
在Flask应用程序中,通常不会这样做。内部重定向(如上所述)的一个示例。但是,即使在这种情况下,你可能最终也会让Flask处理新请求,因此Flask会为你完成所有推送/弹出操作。
但是,在某些情况下,你想自己操作堆栈。
在请求之外运行代码
人们遇到的一个典型问题是,他们使用Flask-SQLAlchemy扩展来使用如下所示的代码来建立SQL数据库和模型定义。
app = Flask(__name__)
db = SQLAlchemy() # Initialize the Flask-SQLAlchemy extension object
db.init_app(app)
然后,它们在应从外壳程序运行的脚本中使用app
和db
值。例如,“ setup_tables.py”脚本…
from myapp import app, db
# Set up models
db.create_all()
在这种情况下,Flask-SQLAlchemy扩展了解app应用程序,但在create_all()此过程中将抛出错误,抱怨没有应用程序上下文。该错误是合理的;你从未告诉Flask在运行该create_all方法时应处理哪个应用程序。
你可能想知道为什么with app.app_context()
在视图中运行类似的函数时最终不需要此调用。原因是Flask在处理实际的Web请求时已经为你处理了应用程序上下文的管理。实际上,问题仅出现在这些视图函数(或其他此类回调)之外,例如在一次性脚本中使用模型时。
解决方案是自己推送应用程序上下文,这可以通过以下方法完成:
from myapp import app, db
# Set up models
with app.app_context():
db.create_all()
这将推送一个新的应用程序上下文(使用的应用程序app,请记住可能有多个应用程序)。
测试中
你想操纵堆栈的另一种情况是进行测试。你可以创建一个处理请求的单元测试,然后检查结果:
import unittest
from flask import request
class MyTest(unittest.TestCase):
def test_thing(self):
with app.test_request_context('/?next=http://example.com/') as ctx:
# You can now view attributes on request context stack by using `request`.
# Now the request context stack is empty
本文向大家介绍介绍一下,堆与栈的不同是什么?相关面试题,主要包含被问及介绍一下,堆与栈的不同是什么?时的应答技巧和注意事项,需要的朋友参考一下 考察点:堆,栈 (1)Java的堆是一个运行时数据区,类的对象从中分配空间。通过比如:new等指令建立,不需要代码显式的释放,由垃圾回收来负责。 优点:可以动态地分配内存大小,垃圾收集器会自动回收垃圾数据。 缺点:由于其优点,所以存取速度较慢。 (2)栈:
这样才是真的。 如果构建过程压缩了当前目录内容并将其发送到守护进程,那么它会去哪里呢?为什么不让这些内容在图像中使用呢?
我在学Windows上的汇编,想弄清楚栈上的值是什么。< br > Visual C #文档说明高于RSP的值是: 分配空间 保存了RBP 返回地址 注册主页(RCX、RDX、R8、R9) 函数参数 问题是堆栈中有32个额外的字节,文档中没有提到。 在内存快照中,RSP从0x0000000000DAF5E0开始。彩色框为: 黄色:两个值为9的64位变量 白色:保存旧RBP返回地址 蓝色:函数参数
问题内容: 在Android编程中,Context类的确切含义是什么? 问题答案: 简单地说: 顾名思义,它是应用程序/对象当前状态的上下文。它使新创建的对象了解正在发生的事情。通常,您调用它来获取有关程序另一部分(活动和程序包/应用程序)的信息。 您可以通过调用获取上下文,,或(当在扩展,从一类Context,如应用程序,活动,服务和IntentService类)。 上下文的典型用法: 创建新对
问题内容: 我正在阅读http://eigenhombre.com/2013/04/20/introduction-to-context- managers/ 。 在里面: 上下文管理器是一种在需要的地方准确分配和释放某种资源的方法。最简单的示例是文件访问: 这基本上等于: 本文继续进行更多的解释,但是我仍然不确定我是否简单地理解了它们的目的。有人可以澄清。还有什么是“上下文”? 我已经看过尝试通
问题内容: 我正在阅读有关JVM体系结构的信息。今天,我了解了操作数堆栈的概念。根据一篇文章: 在字节码指令执行期间使用操作数堆栈,其方式与在本机CPU中使用通用寄存器的方式类似。 我不明白:操作数堆栈到底是什么,以及它在jvm中如何工作? 问题答案: 这是各种单个字节码操作如何获取其输入以及它们如何提供其输出的方式。 例如,考虑将两个s相加的运算。要使用它,您将两个值压入堆栈,然后使用它: 现在