Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么是装饰功能';发生参数错误时未使用的名称?_Python - Fatal编程技术网

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
印刷(环境)#你在这里装东西吗

什么是
更新包装器
?是的,同样的问题。请创建一个。@DanielWalker
update\u wrapper
是标准库的
functools
模块中的一个函数。
functools.wrapps
:@MarkTolonen未包含独立代码,请接受我最诚挚的歉意。我现在已经添加了它。