【问题标题】:FastAPI: global variable vs module variableFastAPI:全局变量与模块变量
【发布时间】:2021-05-26 00:04:23
【问题描述】:

我希望有一个全局变量,仅限于 FastAPI 请求执行,但对多个模块是通用的。下面是一个小例子来解释这个问题:

我用一个主文件 app.py 和一个模块 mymodule 构建了一个非常简单的应用程序。对于每个测试,我使用 1 个工作人员在 uvicorn 中启动应用程序,然后打开 2 个 python 控制台来调用长短调用 requests.get("http://localhost:8000/fakelongcall", {"configtest": "long"} ), requests.get("http://localhost:8000/fakeshortcall", {"configtest": "short"})。

第一种情况:它正在工作,但全局变量 GLOBAL_VAR 不在模块中,因此其他模块无法访问(我可能错了)。

app.py

import time

from fastapi import FastAPI
GLOBAL_VAR = "default"

app = FastAPI()


@app.get("/fakelongcall")
def fakelongcall(configtest: str):
    cpt = 0
    while cpt < 10:
        print(GLOBAL_VAR)
        time.sleep(1)
        cpt = cpt + 1


@app.get("/fakeshortcall")
def fakeshortcall(configtest: str):
    GLOBAL_VAR = configtest
    print("Change done !")

输出

INFO:     Started server process [34182]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
default
default
Change done !
INFO:     127.0.0.1:52250 - "GET /fakeshortcall?configtest=short HTTP/1.1" 200 OK
default
default
default
default
default
default
default
default

第二种情况:两个调用都在更改同一个变量,这不是预期的,但该变量可以在一个很好的模块中访问。

app.py

import time

from fastapi import FastAPI
import mymodule

app = FastAPI()


@app.get("/fakelongcall")
def fakelongcall(configtest: str):
    cpt = 0
    while cpt < 10:
        print(mymodule.GLOBAL_VAR)
        time.sleep(1)
        cpt = cpt + 1


@app.get("/fakeshortcall")
def fakeshortcall(configtest: str):
    mymodule.GLOBAL_VAR = configtest
    print("Change done !")

mymodule.py

GLOBAL_VAR = "默认"

输出

INFO:     Started server process [33994]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
default
default
default
Change done !
INFO:     127.0.0.1:52240 - "GET /fakeshortcall?configtest=short HTTP/1.1" 200 OK
short
short
short
short
short
short
short

为什么会这样? 一名工作人员如何同时执行 2 个电话? 我可以做些什么来获得不同 API 请求之间不共享的模块变量? 为什么在模块中嵌入相同的代码会改变行为?

提前感谢您的帮助。

【问题讨论】:

    标签: python global-variables fastapi


    【解决方案1】:

    这是处理全局变量时的一个典型陷阱。来自FAQ

    在 Python 中,仅在函数内部引用的变量是隐式全局的。如果一个变量在函数体中的任何位置被赋值,除非明确声明为全局变量,否则它被假定为局部变量。

    在第二种情况下,您正在访问导入模块的成员,该成员不会创建局部变量。

    要修复它,请使用 global 关键字:

    def foo():
        global GLOBAL_VAR
        GLOBAL_VAR = configtest
    

    【讨论】:

    • 我得到了与第二种情况相同的结果。更笼统地说,我的问题是:“使用 fastapi 在 python 中定义跨模块但执行特定变量的最佳方法是什么?”
    • 也许我不太明白你的问题。看看context variables。也许这就是您所需要的。
    • 谢谢亚历克斯! Contextvars 是获取线程特定“全局”变量的解决方案。
    【解决方案2】:

    感谢 alex_noname。它适用于上下文变量。

    app.py

    import time
    
    from fastapi import FastAPI
    import mymodule
    
    app = FastAPI()
    
    
    @app.get("/fakelongcall")
    def fakelongcall(configtest: str):
        cpt = 0
        mymodule.var.set(configtest)
        while cpt < 10:
            print(mymodule.var.get())
            time.sleep(1)
            cpt = cpt + 1
    
    
    @app.get("/fakeshortcall")
    def fakeshortcall(configtest: str):
        mymodule.var.set(configtest)
        print("Change done !")
    

    mymodule.py

    from contextvars import ContextVar
    var = ContextVar("var")
    

    输出

    INFO:     Started server process [37237]
    INFO:     Waiting for application startup.
    INFO:     Application startup complete.
    long
    long
    long
    Change done !
    INFO:     127.0.0.1:38680 - "GET /fakeshortcall?configtest=short HTTP/1.1" 200 OK
    long
    long
    long
    long
    long
    long
    long
    long
    INFO:     127.0.0.1:38678 - "GET /fakelongcall?configtest=long HTTP/1.1" 200 OK
    

    【讨论】:

      猜你喜欢
      • 2016-02-10
      • 2015-03-07
      • 1970-01-01
      • 2016-10-20
      • 2016-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-12
      相关资源
      最近更新 更多