[New-bugs-announce] [issue42455] Add decorator_with_params function to functools module

Yurii Karabas report at bugs.python.org
Tue Nov 24 15:34:37 EST 2020


New submission from Yurii Karabas <1998uriyyo at gmail.com>:

In the current python codebases, there are a lot of decorators with parameters, and their code in most cases contains a lot of code boilerplates. The purpose of this issue is to add `decorator_with_params` function to `functools` module. This function will allow using a wrapped function as a simple decorator and decorator with parameter. 

I believe the real example will bring more context, for instance, `typing._tp_cache` function can be rewritten from:
```
def _tp_cache(func=None, /, *, typed=False):
    """Internal wrapper caching __getitem__ of generic types with a fallback to
    original function for non-hashable arguments.
    """
    def decorator(func):
        cached = functools.lru_cache(typed=typed)(func)
        _cleanups.append(cached.cache_clear)

        @functools.wraps(func)
        def inner(*args, **kwds):
            try:
                return cached(*args, **kwds)
            except TypeError:
                pass
            return func(*args, **kwds)
        return inner

    if func is not None:
        return decorator(func)

    return decorator
```
To
```
@decorator_with_params
def _tp_cache(func=None, /, *, typed=False):
    """Internal wrapper caching __getitem__ of generic types with a fallback to
    original function for non-hashable arguments.
    """
    cached = functools.lru_cache(typed=typed)(func)
    _cleanups.append(cached.cache_clear)

    @functools.wraps(func)
    def inner(*args, **kwds):
        try:
            return cached(*args, **kwds)
        except TypeError:
            pass  # All real errors (not unhashable args) are raised below.
        return func(*args, **kwds)

    return inner
```

And `_tp_cache` can be used as:
```
    @_tp_cache(typed=True)
    def __getitem__(self, parameters):
        return self._getitem(self, parameters)
    ...
    @_tp_cache
    def __getitem__(self, parameters):
        return self._getitem(self, parameters)
```

Proposed implementation is quite simple (I used it in a lot of projects):
```
def decorator_with_params(deco):
    @wraps(deco)
    def decorator(func=None, /, *args, **kwargs):
        if func is not None:
            return deco(func, *args, **kwargs)

        def wrapper(f):
            return deco(f, *args, **kwargs)

        return wrapper

    return decorator
```

I believe it will be a great enhancement for the Python standard library and will save such important indentations.

----------
components: Library (Lib)
messages: 381773
nosy: uriyyo
priority: normal
severity: normal
status: open
title: Add decorator_with_params function to functools module
type: enhancement
versions: Python 3.10

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue42455>
_______________________________________


More information about the New-bugs-announce mailing list