classification
Title: Let lru_cache be used as a decorator with no arguments
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.8
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: dino.viehland, eric.smith, eric.snow, giampaolo.rodola, njs, pablogsal, rhettinger, scoder, serhiy.storchaka
Priority: normal Keywords: patch

Created on 2019-05-02 00:40 by rhettinger, last changed 2019-05-26 19:14 by rhettinger. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 13048 merged rhettinger, 2019-05-02 00:44
Messages (10)
msg341239 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-05-02 00:40
Follow the lead of the dataclasses module and allow lru_cache() to be used as a straight decorator rather than as a function that returns a decorator.  Both of these would now be supported:

    @lru_cache
    def f(x):
        ...

    @lru_cache(maxsize=256)
    def f(x):
        ...
msg341246 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-05-02 04:36
I do not like mixing decorators and decorator fabrics. But this can of worms has already been open by dataclasses. The question is whether we want to extend this design to the rest of the stdlib. lru_cache() resisted this change for a long time.
msg341255 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-05-02 08:18
The 90% use case with dataclasses is satisfied with just "@dataclass", and perhaps the target user there is less sophisticated.

But the main difference between @dataclass and @lru_cache is that all of the parameters to @dataclass are keyword-only. Which I did because they are mostly all booleans, and "@dataclass(True, False, True)" isn't very helpful.

That's not the case with @lru_cache. Whether that makes a difference for this issue in particular, I'm not sure.

I agree that this violates "only one way to do it". But I haven't seen anyone use "@dataclass()", and I've also never seen anyone be confused by the fact that once you want parameters, you change to using parens. For the dataclass case, I think that working both ways has been helpful.
msg341266 - (view) Author: Stefan Behnel (scoder) * (Python committer) Date: 2019-05-02 14:14
I'm generally ok with such APIs. It seems needless to require

  @lru_cache()
  def f(): ...

when a simple decorator would suffice. I think I might decide otherwise in cases where almost all usages require arguments, but if the no-arguments case is common (and there is no ambiguity in the arguments), then I prefer not requiring parentheses.
msg341319 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-05-03 01:44
At Pycon today, I mostly got all positive feedback on this.  Apparently py.test already follows this pattern.  Another developer said they found the () to be distracting and would welcome not having to use them.
msg341391 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2019-05-04 15:54
FWIW, I've followed this pattern (one function is both decorator and factory) in my own code for quite a while.  I've never found it confusing nor has anyone else (that I'm aware) that has used those decorators.

One reason I've done decorators this way is because the empty parentheses are a visual distraction to readers.  They also imply to readers that more is going on than really is.  So I'm in favor of Raymond's plan.
msg341392 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2019-05-04 15:58
As to the issue of positional vs. keyword arguments, keyword arguments make the implementation easier in some cases.  Otherwise I haven't seen positional arguments cause much of a problem.
msg341446 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-05-05 13:48
To clarify, I am not opposing this feature. I had doubts because if the memory does not betray me similar propositions for lru_cache or other decorator fabrics were rejected in past. But times change.
msg341569 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2019-05-06 17:31
I am +1 to this. Making it easier for the case of decorator factories that are called with all the defaults is a very common pattern in the wild. There are even known idioms for how to reduce the indentation of the naive approach (returning partials of the factory). In particular for lru_cache, my experience is that every time I teach this feature, people are confused initially about the '()' at the end of the call.
msg343575 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-05-26 18:27
New changeset b821868e6d909f4805499db519ebc2cdc01cf611 by Raymond Hettinger in branch 'master':
bpo-36772 Allow lru_cache to be used as decorator without making a function call (GH-13048)
https://github.com/python/cpython/commit/b821868e6d909f4805499db519ebc2cdc01cf611
History
Date User Action Args
2019-05-26 19:14:29rhettingersetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2019-05-26 18:27:45rhettingersetmessages: + msg343575
2019-05-06 17:31:07pablogsalsetnosy: + pablogsal
messages: + msg341569
2019-05-05 13:48:56serhiy.storchakasetmessages: + msg341446
2019-05-04 15:58:28eric.snowsetmessages: + msg341392
2019-05-04 15:54:18eric.snowsetmessages: + msg341391
2019-05-03 03:02:37gvanrossumsetnosy: - gvanrossum
2019-05-03 01:44:15rhettingersetmessages: + msg341319
2019-05-02 17:50:29rhettingersetnosy: + giampaolo.rodola, dino.viehland, njs, eric.snow
2019-05-02 14:14:31scodersetnosy: + scoder
messages: + msg341266
2019-05-02 08:18:16eric.smithsetmessages: + msg341255
2019-05-02 04:36:15serhiy.storchakasetnosy: + gvanrossum
messages: + msg341246
2019-05-02 00:44:05rhettingersetkeywords: + patch
stage: patch review
pull_requests: + pull_request12967
2019-05-02 00:40:09rhettingercreate