我有python装饰器,我需要将contextVariable作为函数中的参数request_id
传递到我的装饰器中
步骤1:声明contextVariables和方法
_correlation_id_ctx_var: ContextVar[str] = ContextVar(CORRELATION_ID_CTX_KEY, default=None)
_request_id_ctx_var: ContextVar[str] = ContextVar(REQUEST_ID_CTX_KEY, default=None)
def get_correlation_id() -> str:
return _correlation_id_ctx_var.get()
def get_request_id() -> str:
return _request_id_ctx_var.get()
步骤2:我在中间件内部声明的上下文变量(使用FastApi(
@app.middleware("http")
async def log_request(request: Request, call_next):
correlation_id = _correlation_id_ctx_var.set(request.headers.get('X-Correlation-ID', str(uuid4())))
request_id = _request_id_ctx_var.set(str(uuid4()))
步骤3:我尝试将contextVariable传递给decorator-它总是None尝试在函数本身中作为参数传递-它总是None
这是什么问题?
为什么contextVars只能在函数体中访问,而不能在decorator或argument函数中访问?
有什么解决方案可以在函数体之前访问contextVar吗?
@app.get('/test')
@decorator(request_id=get_request_id())
def test_purpose(request_id=get_request_id()):
print('get_correlation_id() start', get_request_id())
return 'ok'
装饰师:
def decorator(request_id=None, *args, **kwargs):
def logger(func, request_id=None, *args, **kwargs):
@wraps(func, *args, **kwargs)
def wrapper(*args, **kwargs):
try:
res = func()
print()
return res
except Exception:
pass
return wrapper
return logger
@decorator(request_id=get_request_id())
<-这一行是在导入模块时执行的。这意味着在导入模块时,getter函数只被调用一次,而不是每次调用装饰函数。
要修复它,只需将getter函数(而不是其结果(传递给decorator,然后在包装器函数内部,在decorator内部进行调用。(为此,只需省略括号(:
def decorator(request_id_getter=None, *d_args, **d_kw):
def logger(func): # other arguments than the first positional arg here are not used at all.
@wraps(func, *d_args, **d_kw)
def wrapper(*args, **kwargs):
request_id = request_id_getter() # and here the value is retrieved when the function is actually called
try:
res = func()
print()
return res
except Exception:
pass
return wrapper
return logger
@app.get('/test')
@decorator(request_id=get_request_id) # <- here is the change - do not _call_ the function!
def test_purpose(request_id=get_request_id()):
print('get_correlation_id() start', get_request_id())
return 'ok'