> Flat is better than nested.

I remember being confused a lot when I was learning how to write my first 
decorator. Now eight years later, with the last two spent full-time writing 
Python, I introduced a bug in production because I forgot to return the inner 
function from within a decorator. 

By introducing multiple parameter lists when defining a function, Scala does a 
great job at improving readability for curried functions 
(https://docs.scala-lang.org/tour/multiple-parameter-lists.html). 
In Python, that could look like e.g.:

def log(level=logging.DEBUG, logger=logging.root)(func)(*args, **kwargs):
    logger.log(level, 'call: %s', func.__qualname__)
    return func(*args, **kwargs)

Which would be sugar for:

def log(level=logging.DEBUG, logger=logging.root):
    def _log(func):
        def __log(*args, **kwargs):
            logger.log(level, 'call: %s', func.__qualname__)
            return func(*args, **kwargs)
        return __log
    return _log

The obvious problem in this example, is that `functools.wraps` is missing. One 
solution would be for me to flex my 8 years of experience, and present these 
two (super/meta-)decorators:

def wraps_decorator(decorator: Callable[[F], F]):
    @functools.wraps(decorator)
    def _wraps_decorator(func):
        return functools.wraps(func)(decorator(func))
    return _wraps_decorator


@wraps_decorator
def wraps_decorator_factory(decorator_factory)(*args, **kwargs):
    return wraps_decorator(decorator_factory(*args, **kwargs))

Applying the latter on the first example, it becomes

@wraps_decorator_factory
def log(level=logging.DEBUG, logger=logging.root)(func)(*args, **kwargs):
    logger.log(level, 'call: %s', func.__qualname__)
    return func(*args, **kwargs)

which is equivalent to:

def log(level=logging.DEBUG, logger=logging.root):
    def _log(func):
        @functools.wraps(func)
        def __log(*args, **kwargs):
            logger.log(level, 'call: %s', func.__qualname__)
            return func(*args, **kwargs)
        return __log
    return _log


Implementation-wise, I think it's very feasible since it's only sugar. And I'm 
sure that the required grammar changes are possible with the shiny new parser.

And considering PEP 659, I can imagine that this syntax is beneficial because 
the closure variables coincide with the parameter lists.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/2HGGXLQGGIUOG2ENLNAAT3YY6GPDD3DF/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to