At present, multi-argument function decorators are a little bit tricky to
implement.
As an example (somewhat contrived), suppose that `wait` is a function
decorator which haults program execution for a few seconds before calling
the wrapped function.
If you do not pass a float value into *delay* then the default value is 1
second.
#EXAMPLE 1A
@wait
def print_something(something):
print (something)
#EXAMPLE 2A
@wait(0.2)
def print_something_else(something):
print (something)
The `@wait` gets implemented almost like the following code:
# EXAMPLE 1B
def print_something(something):
print (something)
print_something = wait(print_something)
# EXAMPLE 2B
temp = wait(0.2)
def print_something_else(something):
print (something)
print_something = temp(print_something)
What is tricky is the following:
* if `Wait` has no arguments: `Wait` is the decorator. else: #
`Wait` receives arguments `Wait` is not the decorator itself.
Instead, `Wait` ***returns*** the decorator*
As a result, people write strange-looking (hard-to-read) decorators, like
the following:
def wait(func=None, delay=1.0):
def decorator_wait(func):
def wrapper_wait(*args, **kwargs):
time.sleep(delay)
return func(*args, **kwargs)
return wrapper_wait
return decorator_wait(func) if func is not None else decorator_wait
This suggestion is that a new operator be introduced. The old @-syntax for
decorators would remain unchanged, preserving backwards compatibility. It
does not really matter to me what string is used for the operator, but I
was thinking *$*, or if not that !@ with an interobang before the @. Our
opening example of how it would work is shown below:
# Example 3A
$dec(1, 2, 3)
def foo():
pass
###########################################
# Example 3B
def foo():
pass
foo = dec(foo, 1, 2, 3)
Examples 3A and 3B are meant to be equivalent. The new decorator operator
would simply pass the decorated function into the decorator as the leftmost
argument.
@wait
def slowly_print_something(something):
print(something)
#--------------------------------
def slowly_print_something(something):
print(something)
slowly_print_something = wait(slowly_print_something)
##################################################
@wait(3.0)
def slowly_print_something_else(something_else):
print(something_else)
#-----------------------------------
def bar(something_else):
print(something_else)
slowly_print_something_else = wait(bar, 3.0)
######################################################
import time
def wait(inny, delay=1.0):
def outty(*args, **kwargs):
time.sleep(delay)
return inny(*args, **kwargs)
return outty
Maybe call them "dollar decorators," or if the !@ syntax is used,
then maybe call them "bang decorators."
I care more about the functionality than the exact strings of symbol
which is used to signal the interpreter what's coming next.
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/TWNRK6ZT3G5FDAMNKJTETE7DOI4VUGBW/
Code of Conduct: http://python.org/psf/codeofconduct/