This would work.
def d(arg):
if callable(arg): # Assumes optional argument isn't.
def newfn():
print('my default message')
return arg()
return newfn
else:
def d2(fn):
def newfn():
print(arg)
return fn()
return newfn
return d2
@d('This is working')
def hello():
print('hello world !')
@d # No explicit arguments will result in default message.
def hello2():
print('hello2 world !')
@d('Applying it twice')
@d('Would also work')
def hello3():
print('hello3 world !')
hello()
hello2()
hello3()
Output:
This is working
hello world !
my default message
hello2 world !
Applying it twice
Would also work
hello3 world !
If a decorator function @invocation isn't passed any explicit arguments, it is called with the function defined in the following def. If it is passed arguments, then it is first called with them and then the result of that preliminary call (which must itself also be a callable) is called with the function being defined. Either way, the return value of the last or only call is bound to the defined function name.