On Wed, May 26, 2021 at 12:43:48PM -0400, Ricky Teachey wrote: [...] > These two ideas of a decorator syntax result are not the same: > > RESULT A: function decorator > # func = decorator("spam")(func) > > RESULT B: variable decorator > # name = decorator("spam")("name") > > ...because func is passed as an object, but "name" a string representing > the name of the object. Two very different things.
Ricky, it's not clear to me whether you are proposing the above RESULT A and RESULT B as an *alternative* to the "variable decorator" proposal, or if you have just misunderstood it. The current variable decorator proposal on the table is for this: @decorator(spam) name # --> name = decorator("name", spam) rather than what you wrote: # name = decorator("spam")("name") So I can't tell whether the difference between your version and the OPs is a bug or a feature :-) > For this reason I think I would agree even more so that the differences in > the decorator behavior would be an extremely significant point of confusion. [...] > Maybe employment of decorator syntax could OPTIONALLY trigger a new dunder > method-- here I'll just call it __decoration_call__-- with the signature: > > def __decoration_call__(self, obj: Any, by_name: str) -> Any: ... To be clear here, I think that your proposal is that this method is to be looked up on the *decorator*, not the thing being decorated. Is that correct? In other words: @decorator class X: ... # or a function, or something else it is *decorator*, not X, that is checked for a `__decoration_call__` method. Correct? > My idea is to optionally allow any callable object to write a > __decoration_call__ method that gets called in lieu of the __call__ method > when the callable object is employed using decorator syntax. When this > happens, the decorated named is supplied- not counting self- as the first > argument (e.g., by_name), which contains the str value of the name the > decorator was applied to. In current Python, the only objects which can be decorated with the @ syntax are callable functions and classes. So it is ambiguous to talk about "any callable object" without stating whether it is the decorator or the thing being decorated. > In actuality, unless I'm wrong (I might be; not an expert) current > decorator syntax is really sugar for: > > def func(): ... > func = decorator.__call__("spam this").__call__(func) Roughly speaking, that would correspond to @decorator("spam this") def func(): ... If we have a bare decorator, we have this: @decorator def func(): ... # --> func = decorator.__call__(func) > My proposal is to make it such that: > > @decorator > def func(): ... > > ...*can result* in this: > > def func(): ... > func = decorator.__decoration_call__( func, "func") Okay. Without reading the source code, does this code snippet use the old `__call__` protocol or the new `__decoration_call__` protocol? @flambé class Banana_Surprise: pass It seems to me that this proposal means that we can't even tell which of the two protocols (classic decoration, or new `__decoration_call__` style decoration) without digging into the implementation of the decorator. To be precise, the problem here as reader isn't so much the fact that I don't know whether the object is called using the `__call__` protocol or the new-style `__decorator_call__` protocol, but the fact that I can't tell whether the calls will involve the name being passed or not. This is because the name is being *implicitly* passed, in a way that is unclear whether or not it will be passed. I just don't know whether or not the decorator `flambé` receives the name or not. > And also so that this: > > @decorator("spam this") > def func(): ... > > ...*can result* in this: > > def func(): ... > func = decorator.__call__("spam this").__decoration_call__(func, "func") What happens if the decorator factory has `__decoration_call__` and the object it returns only has `__call__`? I presume you get this: func = decorator.__decoration_call__("spam this", "func").__call__(func) And let's not forget the other two combinations: func = decorator.__decoration_call__("spam this", "func").__decoration_call__(func, "func") func = decorator.__call__("spam this").__call__(func) The last one is, of course, the current behaviour for a decorator factory. The bottom line here is that is you have plain, unadorned decorator: @decorator there are two possible behaviours and no obvious way to tell which one is used, short of digging into the implementation. But if you have a decorarator factory: @factory(*args, **kwargs) there are now four possible behaviours. And anyone brave enough to use a double-barrelled factory-factory @factory(*args, **kwargs)(*more_args) will be faced with eight possible combinations. And at this point, I'm afraid I have run out of steam to respond further to this proposal. Sorry. -- Steve _______________________________________________ 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/GZQ2RTWVNW6KC2REISB34TLRH45ZJIMK/ Code of Conduct: http://python.org/psf/codeofconduct/