定义了两个函数修饰符. 目标是检测是否对函数应用了0、1或2个修饰符.

为什么下面的代码为第二个装饰者返回"FALSE"?

def decorator1(f):
    def wrapped(*args, **kwargs):
        f(*args, **kwargs)

    wrapped.dec1 = True
    return wrapped


def decorator2(f):
    def wrapped(*args, **kwargs):
        f(*args, **kwargs)

    wrapped.dec2 = True
    return wrapped


@decorator1
@decorator2
def myfunc():
    print(f"running myfunc")


if __name__ == "__main__":
    myfunc()

    print(f"myfunc has decorator1: {getattr(myfunc, 'dec1', False)}")
    print(f"myfunc has decorator2: {getattr(myfunc, 'dec2', False)}")

结果:

running myfunc
myfunc has decorator1: True 
myfunc has decorator2: False

我使用的是Python3.9.

推荐答案

实际上,打印声明中的这句话是不正确的:"myfunc有……".第myfunc号既没有dec1也没有dec2.从调用您的修饰符得到的是一个新函数,而不是您传递的函数.我会解释的.

此代码:

@decorator1
@decorator2
def myfunc():
    print(f"running myfunc")

相当于:

def myfunc():
    print('running myfunc')

myfunc = decorator2(myfunc)
myfunc = decorator1(myfunc)

请记住,您将这些动态属性添加到这wrapped个函数中.它们并不都适用于相同的myfunc函数对象.它们适用于"their"包装函数.包装函数是这两个修饰符中的两个不同对象:

myfunc = decorator2(myfunc)
print(myfunc)   # <function decorator2.<locals>.wrapped at 0x1028456c0>
myfunc = decorator1(myfunc)
print(myfunc)   # <function decorator1.<locals>.wrapped at 0x102845760>

在堆叠装饰物之后,你可以预期decorator1.<locals>.wrapped个有dec1个(因为它是外部的),但它没有dec2个.在decorator2.<locals>.wrapped号公路上:

def decorator1(f):
    def wrapped(*args, **kwargs):
        return f(*args, **kwargs)
    wrapped.dec1 = True
    return wrapped


def decorator2(f):
    def wrapped(*args, **kwargs):
        return f(*args, **kwargs)
    wrapped.dec2 = True
    return wrapped


def myfunc():
    print('running myfunc')


myfunc = decorator2(myfunc)
myfunc = decorator1(myfunc)


print(f"{getattr(myfunc, 'dec1', False)}")  # True
print(f"{getattr(myfunc.__closure__[0].cell_contents, 'dec2', False)}")  # True

如果你有这样的装饰师,你的假设就会奏效:

def decorator1(f):
    f.dec1 = True
    return f

def decorator2(f):
    f.dec2 = True
    return f

@decorator1
@decorator2
def myfunc():
    print('running myfunc')

print(f"{getattr(myfunc, 'dec1', False)}")  # True
print(f"{getattr(myfunc, 'dec2', False)}")  # True

How can you achieve it with your existing code?

我不认为这是一种干净的方式,但如果你愿意的话,它是有效的:

def decorator1(f):
    def wrapped(*args, **kwargs):
        return f(*args, **kwargs)

    while hasattr(f, '__wrapped__'):
        f = f.__wrapped__
    f.dec1 = True
    wrapped.__wrapped__ = f
    return wrapped

def decorator2(f):
    def wrapped(*args, **kwargs):
        return f(*args, **kwargs)

    while hasattr(f, '__wrapped__'):
        f = f.__wrapped__
    f.dec2 = True
    wrapped.__wrapped__ = f
    return wrapped

@decorator1
@decorator2
def myfunc():
    print('running myfunc')

print(f"{getattr(myfunc.__wrapped__, 'dec1', False)}")  # True
print(f"{getattr(myfunc.__wrapped__, 'dec2', False)}")  # True

您可以看到,在While循环中,我深入寻找原始的myfunc并将其添加到返回的包装函数中.另外,我将decX个属性添加到原来的myfunc个属性中.

Python相关问答推荐

如何在句子之间添加空白但忽略链接?

单击cookie按钮,但结果不一致

获取Azure Pipelines以从pyproject.toml(而不是relevments_dev.文本)安装测试环境

如何处理必须存在于环境中但无法安装的Python项目依赖项?

pyautogui.locateOnScreen在Linux上的工作方式有所不同

添加包含中具有任何值的其他列的计数的列

当使用keras.utils.Image_dataset_from_directory仅加载测试数据集时,结果不同

PywinAuto在Windows 11上引发了Memory错误,但在Windows 10上未引发

Gekko:Spring-Mass系统的参数识别

. str.替换pandas.series的方法未按预期工作

为什么符号没有按顺序添加?

如何在虚拟Python环境中运行Python程序?

"使用odbc_connect(raw)连接字符串登录失败;可用于pyodbc"

需要帮助重新调整python fill_between与数据点

可以bcrypts AES—256 GCM加密损坏ZIP文件吗?

在Python中计算连续天数

matplotlib + python foor loop

寻找Regex模式返回与我当前函数类似的结果

在不同的帧B中判断帧A中的子字符串,每个帧的大小不同

Flask Jinja2如果语句总是计算为false&