Author uriyyo
Recipients uriyyo
Date 2020-11-24.20:34:37
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1606250077.84.0.747907374749.issue42455@roundup.psfhosted.org>
In-reply-to
Content
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.
History
Date User Action Args
2020-11-24 20:34:37uriyyosetrecipients: + uriyyo
2020-11-24 20:34:37uriyyosetmessageid: <1606250077.84.0.747907374749.issue42455@roundup.psfhosted.org>
2020-11-24 20:34:37uriyyolinkissue42455 messages
2020-11-24 20:34:37uriyyocreate