Python 为什么是装饰功能';发生参数错误时未使用的名称?
我理解Python 为什么是装饰功能';发生参数错误时未使用的名称?,python,Python,我理解functools.wrapps-用于继承\uuuuuu doc\uuuuuuuu、\uuu name\uuuuuuuuu等属性。但我很难解释为什么会发生以下情况。我在Python中有一个decorator函数: from functools import update_wrapper class Environment: ... def requires_environment(function: Callable) -> Callable: def wrappe
functools.wrapps
-用于继承\uuuuuu doc\uuuuuuuu
、\uuu name\uuuuuuuuu
等属性。但我很难解释为什么会发生以下情况。我在Python中有一个decorator函数:
from functools import update_wrapper
class Environment:
...
def requires_environment(function: Callable) -> Callable:
def wrapped_function(*args, environment, **kwargs):
if not isinstance(environment, Environment):
raise TypeError("The environment keyword argument must be of type Environment.")
kwargs["environment"] = environment
return function(*args, **kwargs)
update_wrapper(wrapped_function, function)
return wrapped_function
然后我用它装饰一个函数:
@requires_environment
def function_with_args(arg1, arg2, environment):
pass
当我没有为我的带有参数的函数提供环境
关键字时,我希望错误消息应该是类型错误:带有参数的函数()
:
我明白了
TypeError: wrapped_function() missing 1 required keyword-only argument: 'environment'
为什么显示的是包装的函数
,而不是带有参数的函数
?如果我打印,去掉@
修饰符的语法糖分,打印函数名,即使在修饰之后,也可以正确地说新包装的函数名是function\u with_args
:
function_with_args(1, 2, Environment.PROD)
function_with_args = requires_environment(function_with_args)
print("After", function_with_args.__name__) # After function_with_args
function_with_args(1, 2, Environment.PROD)
然而,我仍然在TypeError
中看到我的wrapped_函数的名称。为什么会这样
下面是我完整的可复制示例:
from time import perf_counter
from typing import Callable
from enum import Enum
from functools import update_wrapper
class Environment(Enum):
PROD = "PROD"
STAGING = "STAGING"
DEV = "DEV"
def requires_environment(function: Callable) -> Callable:
def wrapped_function(*args, **kwargs):
if "environment" not in kwargs:
raise TypeError(f"{function.__name__}() missing 1 required keyword-only argument: 'environment'")
if not isinstance(kwargs['environment'], Environment):
raise TypeError("The environment keyword argument must be of type Environment.")
return function(*args, **kwargs)
update_wrapper(wrapped_function, function)
return wrapped_function
@requires_environment
def function_with_args(arg1, arg2, environment):
print(f"Inside function {function_with_args.__name__}")
print(f"Docstrings: {function_with_args.__doc__}")
function_with_args(1, 2, Environment.PROD)
此错误消息使用代码对象的名称,而不是函数对象的名称。代码对象不能重命名;即使在functools.update\u wrapper
设置函数的\u name\u
之后,函数的代码对象的co\u name
仍然是wrapped\u函数
。通过使用参数检查函数可以看到这一点
Python 3.10中的这种行为是为了使用函数的\uuu qualname\uu
,更好地消除不同类的同名方法的歧义。让我试试:
传递函数参数时,函数参数如下所示
function_with_args(1, 2, Environment.PROD)
包装器函数将所有输入仅作为参数
def wrapped_function(*args, environment, **kwargs):
如您所见,包装器函数基于键值参数环境
解包所有输入参数。此键之前的所有arg将成为*args
的一部分,此键之后的所有arg将成为*kwargs
包装器函数查找环境=
!所以你总是要像这样通过
function_with_args(1, 2, environment=Environment.PROD)
建议:我会尽量这样做
def wrapped_函数(*args,**kwargs):#这很好!不要在这儿换
...
如果locals()中的'environment':#检查环境键是否传递/定义为args
印刷(环境)#你在这里装东西吗
什么是更新包装器
?是的,同样的问题。请创建一个。@DanielWalkerupdate\u wrapper
是标准库的functools
模块中的一个函数。functools.wrapps
:@MarkTolonen未包含独立代码,请接受我最诚挚的歉意。我现在已经添加了它。