我尝试编写一个小函数,以便更轻松地创建带有参数的装饰器:
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
为前缀的函数时,“decFinal”都会按预期执行,但它的返回值(在我的示例中是 wrapper
内部的 addToDict
永远不会被调用。据我了解, @
装饰器语法应该执行装饰器返回的任何函数。有人可以帮我发现我在这里缺少什么吗?😅 每次 startNotepad
被执行时,我希望看到 wrapper
中的“foo”打印出来了。
编辑:有趣的是,当我尝试调用“isValid”时,“foo”确实会被打印,该“isValid”是用
@addToDict
声明的,不带括号(与 startNotepad
不同)。只是,在这两种情况下,逻辑基本上做了相同的事情,除了 startNotepad 首先需要在 foo 最终被调用之前调用 decFinal
。
您的问题是您将 func 添加到字典中,而不是包装版本中。所以只有
startNotepad()
实际上打印 foo - 因为它是装饰版本,而不是 myDict['notepad']()
- 因为它是原始函数
所以代替这个:
def addToDict(func, key=None, log=None):
print("addToDict")
myDict[key if key else str(random.random())]=func # here, func is original undecorated version!
def wrapper(*args, **kwargs):
print("foo")
if log:
print(log)
func(*args,**kwargs)
return wrapper
你必须添加包装纸。所以该行必须位于本地函数下方:
def addToDict(func, key=None, log=None):
def wrapper(*args, **kwargs):
print("foo")
if log:
print(log)
func(*args,**kwargs)
print("addToDict")
myDict[key if key else str(random.random())]=wrapper # fixed!
return wrapper