Reputation: 437
Basically I want a decorator with an argument list that contains more than just a function to be able to be called from both the @- and regular forms. I've "designed" a quick workaround, but it's ugly and executes a function in @-form immediately, which is an undesired side-effect (that's due to return body_two() of course).
def status_display_with_comment(comment, closure = None):
def body_one(function = None):
def body_two():
print(comment)
#an ugly workaround to be able to run both the @- and regular forms
if function != None:
print("Entering", function.__name__)
function()
print("Exited", function.__name__)
elif closure != None:
print("Entering", closure.__name__)
closure()
print("Exited", closure.__name__)
return body_two()
return body_one
def a_function():
print('a_function executes')
@status_display_with_comment(comment = 'some comment')
def a_function_with_comment():
print('a_function_with_comment executes')
a_function_status_display_with_comment = status_display_with_comment(closure = a_function, comment = 'a comment')
a_function_status_display_with_comment()
Thanks in advance.
P.S.: I have to wrap my head around that whole closure thing. Which is fun considering it could be done recursively like in Scheme (a long time ago for me).
Upvotes: 2
Views: 338
Reputation: 62928
You want a function that returns a decorator:
def status_display_with_comment(comment):
def decorator(function):
def wrapper():
print(comment)
print("Entering", function.__name__)
result = function()
print("Exited", function.__name__)
return result
return wrapper
return decorator
def a_function():
print('a_function executes')
a_function_SD_WC = status_display_with_comment('a comment')(a_function)
a_function_SD_WC()
Also works:
@status_display_with_comment('a comment')
def a_function():
print('a_function executes')
a_function()
The regular, direct decorator already returns a closure:
def a_normal_decorator(function):
def wrapper():
return function()
return wrapper
wrapper
here is a closure since it has to keep function
around even after a_normal_decorator
finished executing.
For reference, this is how an idiomatic decorator is usually written:
import functools
def decorator(function):
@functools.wraps(function)
def wrapper(*a, **kw):
return function(*a, **kw)
return wrapper
That is, it passes arguments to the wrapped function and doesn't throw away its return value.
functools.wraps
copies from the function being wrapped to the wrapper function __name__
, __module__
, __annotations__
and __doc__
, the documentation string.
Upvotes: 6