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/

Reply via email to