You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带可选参数的装饰器返回函数未执行,是否遗漏关键逻辑?

带可选参数装饰器的wrapper函数未执行问题

我写了一个工具函数,用来给普通函数添加可选参数装饰器的语法支持。但发现一个问题:用带参数的装饰器(比如@addToDict("notepad", log="Starting notepad"))装饰的函数,调用时内部的wrapper函数从未执行(看不到"foo"输出);但无参数的@addToDict装饰的函数,调用时wrapper能正常工作。我按照装饰器语法的理解,应该执行装饰器返回的函数,不知道哪里出错了,期望调用startNotepad时能打印wrapper里的"foo"。

工具函数代码

import typing

def decoratorAddSupportForOptionalArguments(addToDict: typing.Callable):
    """Takes a function with arguments, where the first argument is callable and returns a modified version that enables decorator like syntax.
    """
    def addToDictDecorator(*argumentsPassedTo_addToDict, **kargumentsPassedTo_addToDict):
        kargumentsPassedTo_addToDict_keys = kargumentsPassedTo_addToDict.keys()
        if len(argumentsPassedTo_addToDict) == 1 and callable(argumentsPassedTo_addToDict[0]) and 0 == len(kargumentsPassedTo_addToDict_keys):
            returnVal = addToDict(argumentsPassedTo_addToDict[0])
            return returnVal if returnVal != None else addToDict
        # addToDict is being called as a function
        def decFinal(func):
            returnVal = addToDict(func, *argumentsPassedTo_addToDict, **kargumentsPassedTo_addToDict)
            print(f"decFinal {func.__name__} {returnVal}")
            return returnVal if returnVal != None else addToDict
        return decFinal
    return addToDictDecorator

使用示例代码

myDict = dict()
import random

@decoratorAddSupportForOptionalArguments
def addToDict(func, key=None, log=None):
    print("addToDict")
    myDict[key if key else str(random.random())] = func
    def wrapper(*args, **kwargs): # @note This is supposed to be called every time the decorated function gets called.
        print("foo")              # It never gets called however - and I cant figure out whats wrong
        if log:
            print(log)
        func(*args,**kwargs)
    return wrapper

@addToDict
def isValid(value):
    return value != None

@addToDict("myFancyKey")
def isPrivate(value):
    return value.__name__.startswith("_")

@addToDict()
def printRandom(value):
    print(random.random())

@addToDict("notepad", log="Starting notepad")
def startNotepad():
    import os
    print("notepad")
    os.system("notepad.exe")

print(myDict)
myDict["notepad"]()
myDict["notepad"]()
myDict["notepad"]()

问题分析与解决方案

问题根源

核心错误在于addToDict函数中,你把**原始的被装饰函数func**存入了myDict,而不是装饰器返回的wrapper函数。当你调用myDict["notepad"]()时,执行的是未被包装的原始startNotepad函数,自然不会触发wrapper里的"foo"输出。

而无参数装饰的isValid能正常打印"foo",是因为@addToDict语法会把isValid变量替换成wrapper函数——如果你直接调用isValid(),执行的是wrapper;但如果你去myDict里找对应的key调用,同样不会打印"foo",因为字典里存的还是原始func。

解决方案

修改addToDict中存入字典的对象,把func换成wrapper,调整代码顺序确保先定义wrapper再存入:

@decoratorAddSupportForOptionalArguments
def addToDict(func, key=None, log=None):
    print("addToDict")
    def wrapper(*args, **kwargs):
        print("foo")
        if log:
            print(log)
        func(*args,**kwargs)
    # 先定义wrapper,再存入字典
    myDict[key if key else str(random.random())] = wrapper
    return wrapper

这样修改后,myDict里存储的就是包装后的wrapper函数,调用myDict["notepad"]()时就会执行wrapper里的逻辑,打印"foo"和日志信息。

内容的提问来源于stack exchange,提问作者Willy Wonka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 03:33:20