I had a go at writing a little function for making it easier to create decorators with arguments:
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
Which is supposed to be used as following:
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"]()
Every time I attempt executing any of the functions prefixed with addToDict
, "decFinal" gets executed like intended, but its return value (which in my example is wrapper
inside of addToDict
never gets called. To my understanding, the @
decorator syntax should execute any function returned by what is returned by the decorator. What am I missing here? Every time startNotepad
gets executed, I expect to see "foo" from wrapper
get printed.
Interestingly, "foo" does get printed when I try invoking "isValid", which was declared with @addToDict
without the parenthesis (unlike startNotepad
). It's just that, the logic does basically the same thing in both cases, except startNotepad first needs to call decFinal
before foo finally gets called.
Your problem is that you add func to the dictionary, instead of the wrapped version. So only startNotepad()
actually prints foo - because it's decorated version, not myDict['notepad']()
- because it's original function
So instead of this:
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
You gotta add wrapper. So that line had to be below the local function:
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