Flask - 对象仅在请求上下文内更改

问题描述 投票:0回答:1

我在一个大型多线程 Flask 应用程序中遇到了一个奇怪的问题,我已经成功地在大约十几行内重现了该问题。看来,每当我修改与 Flask 中的路由相关的函数内部的对象属性时,该属性只会在该路由函数的上下文中进行修改,而在任何路由函数之外,它都会保留其先前的值。作为示例,这里我使用 __init__.py 和 paths.py 函数在 /app/ 目录中定义了一个“app”包。

应用程序/__init__.py:

from flask import Flask

class NumberStore:
    def __init__(self):
        self.number = 1

    def set_number(self, number):
        self.number = number

app = Flask(__name__)
numberstore = NumberStore()

from app import routes

应用程序/routes.py:

from app import app, numberstore

@app.route('/get')
def get():
    return f"The number holder has id {id(numberstore)} and the number is {numberstore.number}"

@app.route('/set')
def set():
    numberstore.set_number(2)
    return f"The number holder has id {id(numberstore)} and the number has been set to {numberstore.number}"

此外,我有一个方便的脚本,可以在线程中运行服务器:

runserv.py:

import requests
from multiprocessing import Process

from app import app, numberstore

s = Process(target=lambda : app.run())
s.start()

当我在交互式会话中启动服务器并点击“/set”端点时,我期望

numberstore.number
的值更改为 2,对于“/get”和“/set”端点,它确实更改为 2。但是,当我在路由函数的上下文之外访问该对象时,
numberstore.number
的值仍为 1。同样,如果我在交互式会话中手动调用
set_number
方法,更改不会传播到路由函数。尽管对象 ID 在所有情况下都保持不变,但这一切都会发生。由于 ID 指的是对象在内存中的实际位置,这对我来说似乎是不可能的。

laptop:~/testserver$ python3 -i runserv.py 
 * Serving Flask app 'app'
 * Debug mode: off
>>> WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit

>>> numberstore.number
1
>>> id(numberstore)
139855264957008
>>> print(requests.get("http://127.0.0.1:5000/get").text)
The number holder has id 139855264957008 and the number is 1
>>> print(requests.get("http://127.0.0.1:5000/set").text)
The number holder has id 139855264957008 and the number has been set to 2
>>> numberstore.number
1
>>> print(requests.get("http://127.0.0.1:5000/get").text)
The number holder has id 139855264957008 and the number is 2
>>> numberstore.set_number(3)
>>> numberstore.number
3
>>> print(requests.get("http://127.0.0.1:5000/get").text)
The number holder has id 139855264957008 and the number is 2

在我看来,这是一个功能,而不是一个错误,而且我认为它与 Flask 为每个请求启动的请求会话有关。我的问题是 - 为什么 Flask 会这样做,是否有可能规避它?我的真实服务器中几乎所有的操作都是由数据库更改构成的,这显然不存在这个问题。然而,在一个实例中,我确实需要从路由 Flask 端点函数中修改模块级对象的属性。这可以吗?

python flask
1个回答
0
投票

弄清楚了 - Flask 分叉了另一个用于路由端点的进程,但我没有发现它。我没有意识到即使在两个单独的地址空间内对象 ID 也会保持相同。

 python3 -i runserv.py 
 * Serving Flask app 'app'
 * Debug mode: off
>>> WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit

>>> print(requests.get("http://127.0.0.1:5000/get").text)
127.0.0.1 - - [29/Aug/2024 17:18:57] "GET /get HTTP/1.1" 200 -
The number holder has id 139782623142480, the process id is 69246, and the number is 1
>>> import os
>>> os.getpid()
69244

© www.soinside.com 2019 - 2024. All rights reserved.