Decorators for class non function properties

Hi all, Seems like this topic was previously raised, but what if we add possibility to decorate non function properties in class: ```python class Neuron: @linear_activation activation ```

On Tue, Aug 4, 2020 at 6:09 PM <redradist@gmail.com> wrote:
Hi all,
Seems like this topic was previously raised, but what if we add possibility to decorate non function properties in class:
```python class Neuron: @linear_activation activation ```
What would that decoration do, exactly? ChrisA

When one needs a custom property, the easy, readable, and that already works way to create then is just to create an instance of the their class and assign the instance to the desired class attribute. All the class have to do is to have the methods that identify it as a descriptor: "__get__" and "__set__" for data descriptors , and optionally "__del__". The class can be made in a way to make it easier to write the setters and getter , and have their "__set__" and "__get__" call these other methods, but that is about it. ``` class ThresholdProperty: def __init__(self, threshold=0.5): self.threshold = threshold def __set_name__(self, owner, name): self.name = name def __set__(self, instance, value): self.instance.setattr("_" + self.name, value) def __get__(self, instance, owner): if instance is None: return self return int(getattr(instance, "_" + self.name) > self.threshold) class Neuron: activation = ThresholdProperty() ``` On Tue, 4 Aug 2020 at 05:16, Chris Angelico <rosuav@gmail.com> wrote:
On Tue, Aug 4, 2020 at 6:09 PM <redradist@gmail.com> wrote:
Hi all,
Seems like this topic was previously raised, but what if we add
possibility to decorate non function properties in class:
```python class Neuron: @linear_activation activation ```
What would that decoration do, exactly?
ChrisA _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@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/V3HHI4... Code of Conduct: http://python.org/psf/codeofconduct/

Disagree, because for example what if I want custom property with two or three decorators ? Like this: ```python class Neuron: @softmax_activation(weights=["w0", "w1"]) @linear_activation activation def __init__(self): self.w0 = [...] self.w1 = [...] ... ``` or for example I just want to apply to my initializer some decorator: ```python class Neuron: @softmax_activation(weights=["w0", "w1"]) activation = LinearActivation(...) def __init__(self): self.w0 = [...] self.w1 = [...] ... ``` There exist use-cases for this feature ...

Decorator will do the same thing as general decorator For example it could be implemented like this: ```python class linear_activation: def __init(self, name, property): ... def linear_activation(name, property): ... ```

05.08.20 10:36, redradist@gmail.com пише:
Decorator will do the same thing as general decorator
So the code class Neuron: @linear_activation activation would be equivalent to the following code? class Neuron: activation activation = linear_activation(activation) This code does not work unless you define global name "activation", and if define it, the code can be written as class Neuron: activation = linear_activation(activation) I do not see reasons to introduce special syntax for this very specific code.

It could work if we extend syntax like this: ```python class Neuron: activation # By default creates activation with None value activation = linear_activation(activation) ``` and then we could apply as may decorators as needed: ```python class Neuron: activation # By default creates activation with None value activation = linear_activation(activation) activation = softmax_activation(weights=["w0", "w1"])(linear_activation(activation)) ```

On Wed, Aug 5, 2020 at 8:01 PM <redradist@gmail.com> wrote:
It could work if we extend syntax like this: ```python class Neuron: activation # By default creates activation with None value\
Why not just "activation = None"?
activation = linear_activation(activation) ``` and then we could apply as may decorators as needed: ```python class Neuron: activation # By default creates activation with None value activation = linear_activation(activation) activation = softmax_activation(weights=["w0", "w1"])(linear_activation(activation)) ```
You can already do this. ChrisA

But I can do the same thing with class methods ... but anyway it was introduced method decorators to simplify development and add extra power ...

On 5/08/20 9:13 pm, Serhiy Storchaka wrote:
the code can be written as
class Neuron: activation = linear_activation(activation)
I do not see reasons to introduce special syntax for this very specific code.
A considerable number of moons ago, I suggested that @my_property fred = 42 should expand to fred = my_property("fred", 42) The point being to give the descriptor access to the name of the attribute, without having to repeat yourself. -- Greg

On 05.08.20 12:40, Greg Ewing wrote:
On 5/08/20 9:13 pm, Serhiy Storchaka wrote:
the code can be written as
class Neuron: activation = linear_activation(activation)
I do not see reasons to introduce special syntax for this very specific code.
A considerable number of moons ago, I suggested that
@my_property fred = 42
should expand to
fred = my_property("fred", 42)
The point being to give the descriptor access to the name of the attribute, without having to repeat yourself.
That should be possible by doing `fred = my_property(42)` and defining `__set_name__` on the `my_property` class. https://docs.python.org/3/reference/datamodel.html#object.__set_name__

On Wed, 5 Aug 2020 at 13:29, Dominik Vilsmeier <dominik.vilsmeier@gmx.de> wrote:
On 05.08.20 12:40, Greg Ewing wrote:
A considerable number of moons ago, I suggested that
@my_property fred = 42
should expand to
fred = my_property("fred", 42)
The point being to give the descriptor access to the name of the attribute, without having to repeat yourself.
That should be possible by doing `fred = my_property(42)` and defining `__set_name__` on the `my_property` class.
I suppose that what Greg Ewing suggests is a way to define a sort of custom simple statement. For example, instead of the old print "Hello" and the "new" print("Hello") you could write @print "Hello"

On Wed, Aug 5, 2020 at 9:38 AM Marco Sulla <Marco.Sulla.Python@gmail.com> wrote:
On Wed, 5 Aug 2020 at 13:29, Dominik Vilsmeier <dominik.vilsmeier@gmx.de> wrote:
On 05.08.20 12:40, Greg Ewing wrote:
A considerable number of moons ago, I suggested that
@my_property fred = 42
should expand to
fred = my_property("fred", 42)
The point being to give the descriptor access to the name of the attribute, without having to repeat yourself.
That should be possible by doing `fred = my_property(42)` and defining `__set_name__` on the `my_property` class.
I suppose that what Greg Ewing suggests is a way to define a sort of custom simple statement.
For example, instead of the old print "Hello"
and the "new" print("Hello")
you could write
@print "Hello"
What would this print? @print 1, 2, 3 Would we also want to do this? @print() 1, 2, 3 How about this? @print(sep="\n") 1, 2, 3 --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler

On Wed, 5 Aug 2020 at 15:53, Ricky Teachey <ricky@teachey.org> wrote:
How about this?
@print(sep="\n") 1, 2, 3
If you consider @print as a function decorator, it's quite a problem. But I was thinking mainly about a sort of "decorator" for the parser and/or the AST compiler. This could allow you to have, for example: from mypython import * @const a = 5 with a C extension. More than an idea is a question, since I've no knowledge about AST and code parsers.

On Wed, Aug 5, 2020 at 11:41 AM Marco Sulla <Marco.Sulla.Python@gmail.com> wrote:
On Wed, 5 Aug 2020 at 15:53, Ricky Teachey <ricky@teachey.org> wrote:
How about this?
@print(sep="\n") 1, 2, 3
If you consider @print as a function decorator, it's quite a problem. But I was thinking mainly about a sort of "decorator" for the parser and/or the AST compiler. This could allow you to have, for example:
from mypython import * @const a = 5
with a C extension. More than an idea is a question, since I've no knowledge about AST and code parsers.
I'm probably dim but I have no idea what that is supposed to mean or do. Is this just calling const(a=5)...? what is the point of that?

On Wed, Aug 5, 2020 at 1:27 PM Ricky Teachey <ricky@teachey.org> wrote:
On Wed, Aug 5, 2020 at 11:41 AM Marco Sulla <Marco.Sulla.Python@gmail.com> wrote:
On Wed, 5 Aug 2020 at 15:53, Ricky Teachey <ricky@teachey.org> wrote: from mypython import * @const a = 5
I'm probably dim but I have no idea what that is supposed to mean or do. Is this just calling const(a=5)...? what is the point of that?
I'm not advocating it, and I'm not the one that came up with it. But my impression is that it is intended to mean: a = const('a', 5) This doesn't seem completely pointless:
class const(): ... def __init__(self, name, val): ... self.name = name ... self.val = val ... def about(self): ... print(self.name, '=', self.val) ... a = const('a', 5) a.val 5 a.about() a = 5
There might be a way to subclass, e.g. int, so that you don't need to use `a.val` to get the value. It wasn't obvious to me how to do it in pure Python with 3 minutes thought. -- The dead increasingly dominate and strangle both the living and the not-yet born. Vampiric capital and undead corporate persons abuse the lives and control the thoughts of homo faber. Ideas, once born, become abortifacients against new conceptions.

On Wed, Aug 5, 2020 at 1:54 PM David Mertz <mertz@gnosis.cx> wrote:
On Wed, Aug 5, 2020 at 1:27 PM Ricky Teachey <ricky@teachey.org> wrote:
On Wed, Aug 5, 2020 at 11:41 AM Marco Sulla <Marco.Sulla.Python@gmail.com> wrote:
On Wed, 5 Aug 2020 at 15:53, Ricky Teachey <ricky@teachey.org> wrote: from mypython import * @const a = 5
I'm probably dim but I have no idea what that is supposed to mean or do. Is this just calling const(a=5)...? what is the point of that?
I'm not advocating it, and I'm not the one that came up with it. But my impression is that it is intended to mean:
a = const('a', 5)
This doesn't seem completely pointless:
class const(): ... def __init__(self, name, val): ... self.name = name ... self.val = val ... def about(self): ... print(self.name, '=', self.val) ... a = const('a', 5) a.val 5 a.about() a = 5
There might be a way to subclass, e.g. int, so that you don't need to use `a.val` to get the value. It wasn't obvious to me how to do it in pure Python with 3 minutes thought.
Ah, I get it. And btw this works:
class const(int): ... def __new__(cls, name, val): ... obj = super().__new__(cls, val) ... obj.name = name ... return obj ... def about(self): ... print(self.name, '=', self) ... a = const('a', 5) a 5 a.about() a = 5
--- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler

On Wed, Aug 5, 2020 at 2:03 PM Ricky Teachey <ricky@teachey.org> wrote:
And btw this works:
class const(int): ... def __new__(cls, name, val): ... obj = super().__new__(cls, val) ... obj.name = name ... return obj ... def about(self): ... print(self.name, '=', self) ... a = const('a', 5) a 5 a.about() a = 5
That's literally useless, because after running that there is nothing stopping you from doing:
a = 10
or even:
a = "python has no constants"
And now a has a value different from 5. There is nothing even remotely resembling const-ness to that class. In order to get const-ness, you would need the ability to overload assignments, like C++ can do. And Python can't do that, and that's probably a good thing.

If you really want something like this, you can today write: >>> def wibble(fn): ... return ', '.join(fn()) >>> @wibble ... def aaaa(): ... return 'APPLES' >>> aaaa 'A, P, P, L, E, S' This allows you to use a decorator, if that's really what you want to do. The original post asked for @wibble fruit to be equivalent to fruit = wibble(fruit) If there are sufficient examples where this is useful, I say go for it. But only after first trying to get my fruit in some other way. Real world examples where it would be useful are generally worth much more than invented examples. I hope this helps, even if it disappoints. -- Jonathan

On Wed, Aug 5, 2020 at 2:25 PM Jonathan Fine <jfine2358@gmail.com> wrote:
Real world examples where it would be useful are generally worth much more than invented examples.
I agree that @const is not really a useful "value decorator." I was just picking up the example that occurred up-thread. Here's something I think could be more useful (again, I'm +0 at best myself).
@unit("meter") a = 3 # a = unit("meter")("a", 3) @unit("foot") b = 4 # b = unit("foot")("b", 4) a, a.name, a.unit (3, "a", "meter")
Implementation left to reader, but basically it's exactly Ricky's __new__(), just wrapped in a class factory function to parameterize the unit. -- The dead increasingly dominate and strangle both the living and the not-yet born. Vampiric capital and undead corporate persons abuse the lives and control the thoughts of homo faber. Ideas, once born, become abortifacients against new conceptions.

On Wed, Aug 05, 2020 at 02:42:34PM -0400, David Mertz wrote:
Here's something I think could be more useful (again, I'm +0 at best myself).
@unit("meter") a = 3 # a = unit("meter")("a", 3)
Why does the measurement "3 metres" need to know that it is bound to the target name "a"? If you then did: x = a y = a + unit('metre')('b', 0) what would x.name and y.name be? And when would you need to know that? If we're talking about associating units to measurements, surely we don't need anything more than function call syntax or operators: # Something like one or more of these a = unit('metre', 3) b = metres(3) g = 9.8 * metres / seconds**2 for declaring units. -- Steven

On 6/08/20 6:42 am, David Mertz wrote:
@unit("meter") a = 3 # a = unit("meter")("a", 3) @unit("foot") b = 4 # b = unit("foot")("b", 4)
This still doesn't explain why the decorator syntax would be significantly better than just calling the function directly. meters = unit("meter") feet = unit("foot") a = meters(3) b = feet(4) Seems just as readable to me. -- Greg

On Thu, Aug 6, 2020 at 2:52 AM Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
On 6/08/20 6:42 am, David Mertz wrote:
@unit("meter") a = 3 # a = unit("meter")("a", 3) @unit("foot") b = 4 # b = unit("foot")("b", 4)
This still doesn't explain why the decorator syntax would be significantly better than just calling the function directly.
meters = unit("meter") feet = unit("foot")
a = meters(3) b = feet(4)
The only difference is that in the usual existing style, 'a' doesn't know that it's called "a". You and Steven have both, basically, said "Why would you possibly care about that?" And honestly, I don't actually disagree. I was just trying to make a *plausible* case for wanting it to try to extrapolate from the suggestion. I think in the fairly rare case the (original) name matters, attaching it manually is every bit as good. N_a = mol(6.02214076e23) N_a.name = "Avogadro" I think in the oddball corner cases where we might care about the "binding name" inside the object itself, __set_name__() gets us enough. Yes, it's not for globals or locals. But putting that funny extra stuff inside an instance seems like a low burden. -- The dead increasingly dominate and strangle both the living and the not-yet born. Vampiric capital and undead corporate persons abuse the lives and control the thoughts of homo faber. Ideas, once born, become abortifacients against new conceptions.

On 7/08/20 2:47 am, David Mertz wrote:
The only difference is that in the usual existing style, 'a' doesn't know that it's called "a". You and Steven have both, basically, said "Why would you possibly care about that?"
I've only really been thinking about attributes, but I suppose it might be useful for things in other contexts to know their names, so I guess my original proposal is not completely dead. But I don't have any real-world use case to put forward. -- Greg

On Fri, Aug 07, 2020 at 12:22:28PM +1200, Greg Ewing wrote:
On 7/08/20 2:47 am, David Mertz wrote:
The only difference is that in the usual existing style, 'a' doesn't know that it's called "a". You and Steven have both, basically, said "Why would you possibly care about that?"
I've only really been thinking about attributes, but I suppose it might be useful for things in other contexts to know their names, so I guess my original proposal is not completely dead. But I don't have any real-world use case to put forward.
The classic example is namedtuple: myrecord = namedtuple("myrecord", ...) The three-argument form of type() also needs a name argument. On the other hand, it is arguable that the status quo is more flexible, as you don't have to pass the same class name as the variable name you bind to. -- Steven

All, " And Python can't do that, and that's probably a good thing." Johnathan, you are right, I emailed this list a year or so ago with a way to overload assignment and lookup (i.e. what happens when you >>> a) and it was discussed for a while, but ultimately there were reasons (that I largely agree with) why that would be problematic in python. The title was "A proposal (and implementation) to add assignment and LOAD overloading" for anyone wanting to read the reasoning. On Wed, Aug 5, 2020 at 2:13 PM Jonathan Goble <jcgoble3@gmail.com> wrote:
On Wed, Aug 5, 2020 at 2:03 PM Ricky Teachey <ricky@teachey.org> wrote:
And btw this works:
class const(int): ... def __new__(cls, name, val): ... obj = super().__new__(cls, val) ... obj.name = name ... return obj ... def about(self): ... print(self.name, '=', self) ... a = const('a', 5) a 5 a.about() a = 5
That's literally useless, because after running that there is nothing stopping you from doing:
a = 10
or even:
a = "python has no constants"
And now a has a value different from 5.
There is nothing even remotely resembling const-ness to that class. In order to get const-ness, you would need the ability to overload assignments, like C++ can do. And Python can't do that, and that's probably a good thing. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@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/TCW3TA... Code of Conduct: http://python.org/psf/codeofconduct/
-- Nate Lust, PhD. Astrophysics Dept. Princeton University

On 8/5/20 11:11 AM, Jonathan Goble wrote:
That's literally useless, because after running that there is nothing stopping you from doing:
a = 10
or even:
a = "python has no constants"
And now a has a value different from 5.
There is nothing even remotely resembling const-ness to that class. In order to get const-ness, you would need the ability to overload assignments, like C++ can do. And Python can't do that, and that's probably a good thing.
--> from aenum import Constant --> class K(Constant): ... a = 5 ... b = 'hello' ... --> K.a <K.a: 5> --> K.a == 5 True --> K.a - 3 2 --> K.a = 9 Traceback (most recent call last): ... AttributeError: cannot rebind constant <K.a> --> del K.a Traceback (most recent call last): ... AttributeError: cannot delete constant <K.a> However, one can, of course: del K There is only so much one can do. ;-) -- ~Ethan~

On Wed, Aug 5, 2020 at 3:40 PM Ethan Furman <ethan@stoneleaf.us> wrote:
On 8/5/20 11:11 AM, Jonathan Goble wrote:
That's literally useless, because after running that there is nothing stopping you from doing:
a = 10
or even:
a = "python has no constants"
And now a has a value different from 5.
There is nothing even remotely resembling const-ness to that class. In order to get const-ness, you would need the ability to overload assignments, like C++ can do. And Python can't do that, and that's probably a good thing.
--> from aenum import Constant
--> class K(Constant): ... a = 5 ... b = 'hello' ...
--> K.a <K.a: 5>
--> K.a == 5 True
--> K.a - 3 2
--> K.a = 9 Traceback (most recent call last): ... AttributeError: cannot rebind constant <K.a>
--> del K.a Traceback (most recent call last): ... AttributeError: cannot delete constant <K.a>
However, one can, of course:
del K
There is only so much one can do. ;-)
Actually, it is possible to do with Python, using an import hook. See https://aroberge.github.io/ideas/docs/html/constants.html André Roberge
-- ~Ethan~ _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@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/VUZKCK... Code of Conduct: http://python.org/psf/codeofconduct/

On 8/5/20 10:54 AM, David Mertz wrote:
I'm not advocating it, and I'm not the one that came up with it. But my impression is that it is intended to mean:
a = const('a', 5)
This doesn't seem completely pointless:
class const(): ... def __init__(self, name, val): ... self.name = name ... self.val = val ... def about(self): ... print(self.name, '=', self.val) ... a = const('a', 5) a.val 5 a.about() a = 5
There might be a way to subclass, e.g. int, so that you don't need to use `a.val` to get the value. It wasn't obvious to me how to do it in pure Python with 3 minutes thought.
--> from aenum import Constant --> class K(Constant): ... a = 5 ... --> K.a <K.a: 5> --> K.a == 5 True --> K.a - 3 2 -- ~Ethan~

On Wed, 5 Aug 2020 at 20:10, Ethan Furman <ethan@stoneleaf.us> wrote:
--> from aenum import Constant
--> class K(Constant): ... a = 5 ...
This is exactly what I intended. Think if you're able to do: from aenum import const @const a = 5 Notice that I'm using the "at" char because I can't find a better character. I give the rest to your imagination: # previous declarations of x in the same scope are a SyntaxError @var x = None # simulate electrical circuit c = a @nand b # Java style @final class A: @protected _x = 0 # ...maybe someday @int a = 1

...up? On Thu, 6 Aug 2020 at 04:41, Marco Sulla <Marco.Sulla.Python@gmail.com> wrote:
Think if you're able to do:
from aenum import const @const a = 5
Notice that I'm using the "at" char because I can't find a better character.
I give the rest to your imagination:
# previous declarations of x in the same scope are a SyntaxError @var x = None
# simulate electrical circuit c = a @nand b
# Java style @final class A: @protected _x = 0
# ...maybe someday @int a = 1

Well, "up" it's used in forums to draw attention :)

On Mon, Aug 17, 2020 at 10:46:58AM +0200, Marco Sulla wrote:
Well, "up" it's used in forums to draw attention :)
My ex-boss used to do the same thing except he would use "ping" to get attention. But in his case he would quote his previous (unanswered) question, so that we would at least know the context of the ping. Did you have a specific question to be answered or are you just hoping to get people interested in the proposal? -- Steven

On Mon, Aug 17, 2020 at 7:16 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Mon, Aug 17, 2020 at 10:46:58AM +0200, Marco Sulla wrote:
Well, "up" it's used in forums to draw attention :)
My ex-boss used to do the same thing except he would use "ping" to get attention.
But in his case he would quote his previous (unanswered) question, so that we would at least know the context of the ping.
And when someone's your boss, he can reasonably expect/demand an answer, so a context-free "ping" really means "hey guys, you didn't get around to this, and it's important to your jobs". No such obligation on mailing lists like this.
Did you have a specific question to be answered or are you just hoping to get people interested in the proposal?
A proposal that requires syntactic changes, demonstrates no use-cases beyond "wouldn't this be nice", allows us to write Java code in Python, and maybe even in the future, allows us to do what we can already do with type annotations? I'm amazed python-ideas hasn't already had a hundred-post thread on the subject! ChrisA only half joking, too...

The fact of the matter is that you need (at least) two things to get something new into Python: 1) a good idea that folks will support 2) A "champion" -- someone to keep the conversation going, maybe write a PEP, etc. No matter how great an idea is, it takes a lot of work to get it to a consensus and get it done. For this idea, no one has stepped up to that role, so it petered out -- which is not uncommon on this list. -CHB On Mon, Aug 17, 2020 at 3:49 AM Chris Angelico <rosuav@gmail.com> wrote:
On Mon, Aug 17, 2020 at 7:16 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Mon, Aug 17, 2020 at 10:46:58AM +0200, Marco Sulla wrote:
Well, "up" it's used in forums to draw attention :)
My ex-boss used to do the same thing except he would use "ping" to get attention.
But in his case he would quote his previous (unanswered) question, so that we would at least know the context of the ping.
And when someone's your boss, he can reasonably expect/demand an answer, so a context-free "ping" really means "hey guys, you didn't get around to this, and it's important to your jobs". No such obligation on mailing lists like this.
Did you have a specific question to be answered or are you just hoping to get people interested in the proposal?
A proposal that requires syntactic changes, demonstrates no use-cases beyond "wouldn't this be nice", allows us to write Java code in Python, and maybe even in the future, allows us to do what we can already do with type annotations? I'm amazed python-ideas hasn't already had a hundred-post thread on the subject!
ChrisA only half joking, too... _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@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/UKXMMB... Code of Conduct: http://python.org/psf/codeofconduct/
-- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

Actually, I would like to write a proposal ... It would be nice if someone support me with it because I will do it at first time ... )

On Sat, Aug 22, 2020 at 10:50:28PM -0000, redradist@gmail.com wrote:
Actually, I would like to write a proposal ... It would be nice if someone support me with it because I will do it at first time ... )
Okay, the first step is to familiarise yourself with the way the PEPs are written: https://www.python.org/dev/peps/ Read some PEPs, especially newer, and successful, ones to get an idea of the kinds of things you will need to discuss. E.g. motivation for why you want this feature, use-cases, past history of the discussion, arguments in favour, arguments against, what other languages do, etc. Most important is to have a good explanation of what the feature will do and how it works. Preferably, you will have some idea of whether this is technically possible or not, but someone will soon tell you if it isn't. Second step is to run those ideas past us on this mailing list to see if there is interest. You don't have to write a full, formal, PEP at this point, but you should still have the explanation and use-cases ready. After discussion here, if there are people interested and in favour of the idea, then you can ask for somebody to sponsor a PEP. Ideally you will have overwhelming support and everyone says "that's a great idea, let's do it!" but more likely you'll have a mix of people for and against. -- Steve

On Sun, Aug 23, 2020 at 10:29 AM Steven D'Aprano <steve@pearwood.info> wrote:
After discussion here, if there are people interested and in favour of the idea, then you can ask for somebody to sponsor a PEP. Ideally you will have overwhelming support and everyone says "that's a great idea, let's do it!" but more likely you'll have a mix of people for and against.
Specifically, you have to have one of the core Python developers (or one of a handful of other people, depending on context) to sponsor your PEP. My recommendation: Even though he isn't the final arbiter of the project any more, Guido is still an incredibly smart person, with a lot of experience in language design, so you should probably take notice of his words. See his earlier post in this thread. :) ChrisA

It's unlikely that any proposal for importing syntax macros will be accepted, let alone one as poorly thought-out as this one. The only reason for advising to attempt to write a more formal proposal in this case would be to cause the volunteer to realize just how poorly prepared they are for proposing such a change. It would be friendlier to point this out more directly. I'm not against the occasional bit of Socratic advice, but IMO this is just too large of a step to expect either redradrist or Marco Sulla to take. On Sat, Aug 22, 2020 at 5:29 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Sat, Aug 22, 2020 at 10:50:28PM -0000, redradist@gmail.com wrote:
Actually, I would like to write a proposal ... It would be nice if someone support me with it because I will do it at first time ... )
Okay, the first step is to familiarise yourself with the way the PEPs are written:
https://www.python.org/dev/peps/
Read some PEPs, especially newer, and successful, ones to get an idea of the kinds of things you will need to discuss. E.g. motivation for why you want this feature, use-cases, past history of the discussion, arguments in favour, arguments against, what other languages do, etc.
Most important is to have a good explanation of what the feature will do and how it works.
Preferably, you will have some idea of whether this is technically possible or not, but someone will soon tell you if it isn't.
Second step is to run those ideas past us on this mailing list to see if there is interest. You don't have to write a full, formal, PEP at this point, but you should still have the explanation and use-cases ready.
After discussion here, if there are people interested and in favour of the idea, then you can ask for somebody to sponsor a PEP. Ideally you will have overwhelming support and everyone says "that's a great idea, let's do it!" but more likely you'll have a mix of people for and against.
-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@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/3ARH7X... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

On Sun, 23 Aug 2020 at 02:42, Guido van Rossum <guido@python.org> wrote:
IMO this is just too large of a step to expect either redradrist or Marco Sulla to take.
You're quite right, I have proposed it to have an opinion by experts. Indeed I have no knowledge about how a parser works. This is why I asked if this is possible and desirable. Anyway, I was not thinking about a macro system, but about custom keywords. Maybe a macro is more simple, but was not my idea. My idea is to be able to delegate the parsing of a piece of code to a custom parser, defined in a third-party module. Cython, for example, uses its parser to compile Python code to C code. Cython uses custom keywords like cdef to speed up the code introducing C static typing. My idea and question is if it's possible to have something like this: from cython import * @int a = 0 About Jython and other implementations, as far as I know they can't use C extensions. Not without many troubles.

Little errata: change Cython, for example, uses its parser to compile Python code to Cython, for example, uses its parser to compile Cython code

On Mon, 17 Aug 2020 at 11:17, Steven D'Aprano <steve@pearwood.info> wrote:
Did you have a specific question to be answered or are you just hoping to get people interested in the proposal?
It seems I have to repost the proposal I already wrote... My proposal is to add a way for third party modules to add custom keywords. Example: from mykeywords import @const @const a = 1 Notice that I choose "@" but I hope another non c-alphanumeric character will be chosen. On Mon, 17 Aug 2020 at 12:46, Chris Angelico <rosuav@gmail.com> wrote:
A proposal that requires syntactic changes [...]
No syntactic changes are needed. Custom keywords *must* be prefixed with a non-alphanumeric character (@ for example). ACK

Please try to learn how to write a good proposal. A few examples, like you did here, just isn't enough. It's worth doing right, and it's worth *learning* how to do it right. On Mon, Aug 17, 2020 at 1:03 PM Marco Sulla <Marco.Sulla.Python@gmail.com> wrote:
On Mon, 17 Aug 2020 at 11:17, Steven D'Aprano <steve@pearwood.info> wrote:
Did you have a specific question to be answered or are you just hoping to get people interested in the proposal?
It seems I have to repost the proposal I already wrote...
My proposal is to add a way for third party modules to add custom keywords. Example:
from mykeywords import @const @const a = 1
Notice that I choose "@" but I hope another non c-alphanumeric character will be chosen.
On Mon, 17 Aug 2020 at 12:46, Chris Angelico <rosuav@gmail.com> wrote:
A proposal that requires syntactic changes [...]
No syntactic changes are needed. Custom keywords *must* be prefixed with a non-alphanumeric character (@ for example).
ACK _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@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/NUAHVS... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

On Mon, 17 Aug 2020 at 22:10, Guido van Rossum <guido@python.org> wrote:
Please try to learn how to write a good proposal. A few examples, like you did here, just isn't enough. It's worth doing right, and it's worth *learning* how to do it right.
Well, I'll try. In pure python, you can change everything. It seems that the only things you can't really modify are the keywords. And this is for obvious reasons, since if you change the keywords, the code will be absolutely unreadable. We could add a way to define new keywords using a third-party module; but what if the keyword is already presented as variable, class, function etc. name? So my idea is that these custom keywords must start with a non-alphanumeric character (and underscore). For now, I'll call this char "@" For example, many py programmers desider to make their objects a constant. This could be done in the example I wrote before: from mykeywords import @const @const a = 1 The new `@const` will be added as a hook to the PEG parser. if the PEG parser finds a `@const`, it will invoke the miniparser of `mykeywords` module inherent to `@const`. In this case, it will simply transform `@const a = 1` in `const PyObject* a = PyLong_FromSsize_t((Py_ssize_t) 1)` A problem is that, since `a` now is const, it can't be reassigned. I'm not an expert about parsers, so I ask for info.

On 18/08/20 5:39 pm, Marco Sulla wrote:
The new `@const` will be added as a hook to the PEG parser. if the PEG parser finds a `@const`, it will invoke the miniparser of `mykeywords` module inherent to `@const`.
I don't think this is likely to be accepted into the language. Guido has always been against any form of programmable syntax. There are third party tools such as Macropy for those who want to do this kind of thing. -- Greg

On Tue, Aug 18, 2020 at 07:39:29AM +0200, Marco Sulla wrote:
For example, many py programmers desider to make their objects a constant. This could be done in the example I wrote before:
from mykeywords import @const @const a = 1
The new `@const` will be added as a hook to the PEG parser. if the PEG parser finds a `@const`, it will invoke the miniparser of `mykeywords` module inherent to `@const`. In this case, it will simply transform `@const a = 1` in `const PyObject* a = PyLong_FromSsize_t((Py_ssize_t) 1)`
How does the parser know how to do that? You and I know that "const" means "constant", and you know how to implement that in the C code. What happens if I run that in Jython or IronPython? What if the keyword is `@qwerty`, how does the compiler know what to do? -- Steve

On Tue, Aug 18, 2020 at 6:01 AM Marco Sulla <Marco.Sulla.Python@gmail.com> wrote:
On Mon, 17 Aug 2020 at 11:17, Steven D'Aprano <steve@pearwood.info> wrote:
Did you have a specific question to be answered or are you just hoping to get people interested in the proposal?
It seems I have to repost the proposal I already wrote...
My proposal is to add a way for third party modules to add custom keywords. Example:
from mykeywords import @const @const a = 1
But why? What is the use-case?
Notice that I choose "@" but I hope another non c-alphanumeric character will be chosen.
On Mon, 17 Aug 2020 at 12:46, Chris Angelico <rosuav@gmail.com> wrote:
A proposal that requires syntactic changes [...]
No syntactic changes are needed. Custom keywords *must* be prefixed with a non-alphanumeric character (@ for example).
This IS a syntactic change. You're proposing things that currently aren't legal:
from mykeywords import @const File "<stdin>", line 1 from mykeywords import @const ^ SyntaxError: invalid syntax
A non-syntactic change would be something like this:
from math import fft Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: cannot import name 'fft' from 'math' (/usr/local/lib/python3.10/lib-dynload/math.cpython-310-x86_64-linux-gnu.so)
If you were to propose adding a Fast Fourier Transform function to the math module, that wouldn't require any changes to syntax. If you propose adding a dict.fromvalues method to mirror the fromkeys method, that wouldn't require any changes to syntax. But you're suggesting something that would be syntactically invalid in all previous versions of Python. And you still haven't said why it would be useful. Just "hey look we'd be able to... uhh... do custom keywords". That's not a justification. ChrisA

On Mon, Aug 17, 2020 at 5:02 PM Marco Sulla <Marco.Sulla.Python@gmail.com> wrote:
On Mon, 17 Aug 2020 at 11:17, Steven D'Aprano <steve@pearwood.info> wrote:
Did you have a specific question to be answered or are you just hoping to get people interested in the proposal?
It seems I have to repost the proposal I already wrote...
My proposal is to add a way for third party modules to add custom keywords.
You can already do something like this, using either an import hook or a custom encoding. Perhaps I should repost a link that I already included in an earlier, but rather terse, reply on this thread, about the specific "constant" example. See: https://aroberge.github.io/ideas/docs/html/ You will find various examples of adding custom keywords. (more below)
Example:
from mykeywords import @const @const a = 1
Notice that I choose "@" but I hope another non c-alphanumeric character will be chosen.
On Mon, 17 Aug 2020 at 12:46, Chris Angelico <rosuav@gmail.com> wrote:
A proposal that requires syntactic changes [...]
No syntactic changes are needed. Custom keywords *must* be prefixed with a non-alphanumeric character (@ for example).
Syntactic changes would be needed. The way that your example would be normally processed by Python is as follows: First, the entire content of the file would be read, and broken up into tokens (individual words and symbols). Next, these tokens would be interpreted according to Python's grammar: your notation would raise a SyntaxError. This would stop the entire process. To actually do the import "from mykeywords import ...", one needs to go beyond the parsing stage. This is where a custom encoding or an import hook can help, by transforming the source into valid Python code before it is parsed. More information available at the link given above. André Roberge
ACK _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@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/NUAHVS... Code of Conduct: http://python.org/psf/codeofconduct/

On 6/08/20 1:35 am, Marco Sulla wrote:
I suppose that what Greg Ewing suggests is a way to define a sort of custom simple statement.
you could write
@print "Hello"
My suggestion was only for decorating assignments to a bare name, so that wouldn't have been legal. But that was long before __set_name__ existed. It wouldn't be necessary now for the use case I had in mind, and I can't think of any other reason to want it. -- Greg

On Wed, Aug 05, 2020 at 03:35:15PM +0200, Marco Sulla wrote: [Greg Ewing]
A considerable number of moons ago, I suggested that
@my_property fred = 42
should expand to
fred = my_property("fred", 42)
The point being to give the descriptor access to the name of the attribute, without having to repeat yourself.
[Dominik Vilsmeier]:
That should be possible by doing `fred = my_property(42)` and defining `__set_name__` on the `my_property` class.
Just because you define your own dunder method (which you shouldn't do, since dunders are reserved for the interpreter's use) doesn't make something which is a syntax error stop being a syntax error. [Marco Sulla]
I suppose that what Greg Ewing suggests is a way to define a sort of custom simple statement.
For example, instead of the old print "Hello"
and the "new" print("Hello")
you could write
@print "Hello"
Perhaps you should re-read Greg's proposal again. I've left it quoted above. This is a proposal for decorator syntax, not a new way to call objects for their side-effects. If there's no assignment, it isn't going to work, it's still going to be a syntax error. This would work: @print word = "Hello" but it would print "word Hello", and assign None to `word`. So no, Greg's proposal is nothing like a "custom simple statement", it is a proposal for an extension of decorator syntax to simple assignments. Your version would be a syntax error, because there is no assignment and no target name. -- Steven

On Thu, Aug 6, 2020 at 11:11 AM Steven D'Aprano <steve@pearwood.info> wrote:
[Dominik Vilsmeier]:
That should be possible by doing `fred = my_property(42)` and defining `__set_name__` on the `my_property` class.
Just because you define your own dunder method (which you shouldn't do, since dunders are reserved for the interpreter's use) doesn't make something which is a syntax error stop being a syntax error.
This isn't "defining your own dunder". The syntax as described already works inside a class: class my_property: def __init__(self, n): self.n = n def __set_name__(self, cls, name): print("I'm a property %r on class %s" % (name, cls.__name__)) class X: fred = my_property(42) I'm a property 'fred' on class X But AIUI this is implemented by type.__new__, so there's no useful way to extend this to globals and/or locals. ChrisA

On Thu, Aug 06, 2020 at 11:22:38AM +1000, Chris Angelico wrote:
On Thu, Aug 6, 2020 at 11:11 AM Steven D'Aprano <steve@pearwood.info> wrote:
[Dominik Vilsmeier]:
That should be possible by doing `fred = my_property(42)` and defining `__set_name__` on the `my_property` class.
Just because you define your own dunder method (which you shouldn't do, since dunders are reserved for the interpreter's use) doesn't make something which is a syntax error stop being a syntax error.
This isn't "defining your own dunder". The syntax as described already works inside a class:
class my_property: def __init__(self, n): self.n = n def __set_name__(self, cls, name): print("I'm a property %r on class %s" % (name, cls.__name__))
class X: fred = my_property(42)
I'm a property 'fred' on class X
*blinks* When did this happen? I'm on Python-Ideas, Python-Dev, and I get announcements of new issues on the bug tracker, and I don't recall ever seeing this feature discussed. [looks up the docs] Okay, apparently it was added in 3.6. But the documentation says: """ When using the default metaclass type, or any metaclass that ultimately calls type.__new__, the following additional customisation steps are invoked after creating the class object: first, type.__new__ collects all of the descriptors in the class namespace that define a __set_name__() method; """ https://docs.python.org/3/reference/datamodel.html#class-object-creation but that's not what is happening here, since my_property is not a descriptor, it's just an arbitrary instance. (To be a descriptor, it needs to have `__get__` and/or `__set__` methods.) Have I missed something or does this need a documentation fix? -- Steven

On Wed, Aug 5, 2020 at 7:06 PM Steven D'Aprano <steve@pearwood.info> wrote:
*blinks*
When did this happen?
I'm on Python-Ideas, Python-Dev, and I get announcements of new issues on the bug tracker, and I don't recall ever seeing this feature discussed.
Oddly I barely recall it either, even though according to PEP 487 it was posted five times to python-dev, and I approved it. It's a long time ago though (two retirements, for me :-).
[looks up the docs]
Okay, apparently it was added in 3.6. But the documentation says:
""" When using the default metaclass type, or any metaclass that ultimately calls type.__new__, the following additional customisation steps are invoked after creating the class object:
first, type.__new__ collects all of the descriptors in the class namespace that define a __set_name__() method; """
https://docs.python.org/3/reference/datamodel.html#class-object-creation
but that's not what is happening here, since my_property is not a descriptor, it's just an arbitrary instance.
(To be a descriptor, it needs to have `__get__` and/or `__set__` methods.)
Have I missed something or does this need a documentation fix?
That's a good observation. I think the PEP was only thinking of descriptors, and the implementation possibly took a shortcut by calling `__set_name__` on every attribute. Or perhaps the PEP was ambiguous, since under proposal, item (2) states that the "hook is called on all the attributes (descriptors) defined in the class". Now there's a general rule that says "if you use a dunder in a way that's undocumented, the behavior is undefined" (and this includes making up your own dunders), which means that technically the implementation could do whatever it wants -- but since this is Python we probably want to accept that it's called for every attribute, whether it smells like a descriptor or not, and it would be nice to fix the docs. Do you have the powers to submit PRs these days? -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

On Thu, 6 Aug 2020 at 00:14, Guido van Rossum <guido@python.org> wrote:
On Wed, Aug 5, 2020 at 7:06 PM Steven D'Aprano <steve@pearwood.info> wrote:
*blinks*
When did this happen?
I'm on Python-Ideas, Python-Dev, and I get announcements of new issues on the bug tracker, and I don't recall ever seeing this feature discussed.
Oddly I barely recall it either, even though according to PEP 487 it was posted five times to python-dev, and I approved it. It's a long time ago though (two retirements, for me :-).
I think that __set_name__ was greatly expected as one way to mitigate `DRY` with descriptors it was completely uncontroversial - unlike __init_subclass__ on the same PEP. I for one had used it a lot of times, and I am a big fan of __set_name__ --
--Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...> ____________

On Wed, Aug 05, 2020 at 10:40:02PM +1200, Greg Ewing wrote:
A considerable number of moons ago, I suggested that
@my_property fred = 42
should expand to
fred = my_property("fred", 42)
That require two different rules for decorators: @decorator over a `class name` or `def name` statement: - execute the statement - bind `name = decorator(name)` @decorator over a binding `target = expression`: - bind `target = decorator("target", expression)` So we're adding significant complexity to the concept of "decorator".
The point being to give the descriptor access to the name of the attribute, without having to repeat yourself.
There is a conflict here between DRY and Explicit Is Better Than Implicit. In the case of function and class decorators, the factor that tips it over the edge is not the repeating of the name, but that decorator syntax puts critical information about the object up front, near the signature, instead of hidden way down the bottom where is can be missed: @property def thing(self): # fifty lines of code makes it obvious that `thing` is a property to even the most lazy and careless reader. If the call to property followed the method declaration and it's implementation, it would be far away from the signature, obscuring the fact that `thing` is not just a method but a property. There is no such advantage for this suggested decorator syntax: name = my_property('name', *args, **kw) is at worst a trivial violation of DRY, and it may not even be that[1], but is completely flexible in how many positional and keyword arguments it receives. Whereas: @my_property name = arg takes twice as many lines, can only accept a single positional argument, loses on the "Explicit versus Implicit" question, and saves at best only a trivial and inconsequential DRY violation. So unlike the function/class case, where the benefit is both two-fold and large, the benefit here is only single and tiny, and in my opinion, outweighed by the disadvantages. [1] See discussion here: http://wiki.c2.com/?DontRepeatYourself in particular "It's okay to have mechanical, textual duplication". In this case, the single source of truth is the target name: name = my_property("name", arg) with the duplication being a single word, mechanically copied into the same line. A minor annoyance, but not a DRY violation in any meaningful sense. -- Steven

On Wed, Aug 5, 2020 at 5:55 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Wed, Aug 05, 2020 at 10:40:02PM +1200, Greg Ewing wrote:
A considerable number of moons ago, I suggested that
@my_property fred = 42
should expand to
fred = my_property("fred", 42)
That require two different rules for decorators:
@decorator over a `class name` or `def name` statement:
- execute the statement - bind `name = decorator(name)`
But that's not what's done. (Proof: if the decorator raises, the name remains unbound.)
@decorator over a binding `target = expression`:
- bind `target = decorator("target", expression)`
So we're adding significant complexity to the concept of "decorator".
(That said, I'm not a fan of decorating assignments. The reason we invented decorators in the first place doesn't apply here.) -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

On Wed, Aug 05, 2020 at 06:15:22PM -0700, Guido van Rossum wrote:
On Wed, Aug 5, 2020 at 5:55 PM Steven D'Aprano <steve@pearwood.info> wrote:
That require two different rules for decorators:
@decorator over a `class name` or `def name` statement:
- execute the statement - bind `name = decorator(name)`
But that's not what's done. (Proof: if the decorator raises, the name remains unbound.)
You are technically correct, which is the best kind of correct. The documentation uses very close to the same wording as me https://docs.python.org/3/reference/compound_stmts.html#function-definitions but does make the point that "except that the original function is not temporarily bound to the name func". Since I wasn't writing a reference manual, I didn't think this level of pedantry was needed :-) The bottom line is that the function or class statement has to be executed *in some sense* in order to create the function or class object, that object has to be passed to the decorator, and finally the object returned by the decorator has to be bound to the original name. -- Steven

On Wed, Aug 5, 2020 at 6:42 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Wed, Aug 05, 2020 at 06:15:22PM -0700, Guido van Rossum wrote:
On Wed, Aug 5, 2020 at 5:55 PM Steven D'Aprano <steve@pearwood.info> wrote:
That require two different rules for decorators:
@decorator over a `class name` or `def name` statement:
- execute the statement - bind `name = decorator(name)`
But that's not what's done. (Proof: if the decorator raises, the name remains unbound.)
You are technically correct, which is the best kind of correct.
The documentation uses very close to the same wording as me
https://docs.python.org/3/reference/compound_stmts.html#function-definitions
but does make the point that "except that the original function is not temporarily bound to the name func". Since I wasn't writing a reference manual, I didn't think this level of pedantry was needed :-)
The bottom line is that the function or class statement has to be executed *in some sense* in order to create the function or class object, that object has to be passed to the decorator, and finally the object returned by the decorator has to be bound to the original name.
But that's the same as it would be for a decorated assignment, right? In ``` @deco x = func(arg) ``` This executes `func(arg)` to create the value of the expression, then passes it to the decorator, and finally the decorator's result is bound to the name `x`. In both cases there's something that gets executed to create something (in one case, a function or class object, in another case, some other object), and then gets bound to a name; in both cases a decorator, if present, is inserted to transform the value just before it is bound. A much better argument against decorating assignments is that you can already write it just fine as ``` x = deco(func(arg)) ``` and the decorated version is in no way more readable, nor does it provide more power or expressivity. For functions and classes, the old way was ``` def f(a, b, c): <20 lines of body code> f = deco(f) ``` which hides the decorator call where it is easily overlooked (especially by people who are quickly scanning code for function definitions). The decorator syntax was introduced so that the transformation could be placed where it is noticed by the reader. Another way of looking at the difference between decorating expressions vs. decorating function/class definitions would be that syntactically, `def` and `class` statements are multi-line definitions, so that it makes sense that a modifier should be placed on a line by itself; whereas assignments are single-line definitions, so that modifiers should also be placed in-line. -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

On 06.08.20 04:58, Guido van Rossum wrote:
On Wed, Aug 5, 2020 at 6:42 PM Steven D'Aprano <steve@pearwood.info <mailto:steve@pearwood.info>> wrote:
On Wed, Aug 05, 2020 at 06:15:22PM -0700, Guido van Rossum wrote: > On Wed, Aug 5, 2020 at 5:55 PM Steven D'Aprano <steve@pearwood.info <mailto:steve@pearwood.info>> wrote:
> > That require two different rules for decorators: > > > > @decorator over a `class name` or `def name` statement: > > > > - execute the statement > > - bind `name = decorator(name)` > > > > But that's not what's done. (Proof: if the decorator raises, the name > remains unbound.)
You are technically correct, which is the best kind of correct.
The documentation uses very close to the same wording as me
https://docs.python.org/3/reference/compound_stmts.html#function-definitions
but does make the point that "except that the original function is not temporarily bound to the name func". Since I wasn't writing a reference manual, I didn't think this level of pedantry was needed :-)
The bottom line is that the function or class statement has to be executed *in some sense* in order to create the function or class object, that object has to be passed to the decorator, and finally the object returned by the decorator has to be bound to the original name.
But that's the same as it would be for a decorated assignment, right? In ``` @deco x = func(arg) ``` This executes `func(arg)` to create the value of the expression, then passes it to the decorator, and finally the decorator's result is bound to the name `x`.
In both cases there's something that gets executed to create something (in one case, a function or class object, in another case, some other object), and then gets bound to a name; in both cases a decorator, if present, is inserted to transform the value just before it is bound.
A much better argument against decorating assignments is that you can already write it just fine as ``` x = deco(func(arg)) ``` and the decorated version is in no way more readable, nor does it provide more power or expressivity.
It seems that the OP has many such transformations and wants to use decorators to define a pipeline of transformations: @foo @bar @baz something = initial_value instead of something = foo(bar(baz(initial_value))) which becomes unreadable for longer function names / more functions in general. However one can always define such pipelines in advance and then apply them when needed: pipeline = Pipeline(foo, bar, baz) something = pipeline(initial_value) For single usage one can even define such a pipeline via decorators by using a function to provide the initial value: @foo @bar @baz @pipeline def something(): return initial_value where `pipeline` simply returns the return value of the function it's applied to.

On Thu, Aug 06, 2020 at 09:57:59AM +0200, Dominik Vilsmeier wrote:
It seems that the OP has many such transformations and wants to use decorators to define a pipeline of transformations:
@foo @bar @baz something = initial_value
instead of
something = foo(bar(baz(initial_value)))
which becomes unreadable for longer function names / more functions in general.
something = \ foo( bar( baz( initial_value ))) is possible right now, and the style is not that far off the suggested decorator syntax. Decorator syntax is a great hammer, and functions and classes make good nails. Arbitrary function calls are not good nails, there is no need to use a hammer on them. -- Steven

I think a property decorator can be useful, because you consider the simplest case with: ```python class MyClass: @my_property name = arg ``` but consider it can generate the following code: ```python class MyClass: def name(self): ... def see_name(self): ... ``` Or consider the following example: ```python class MyClass: @factory strategy= arg ``` that can will generate: ```python class MyClass: class MyClassStrategy: ... strategy= MyClassStrategy(arg) ``` All it will be possible if attribute decorator will have the following signature: ```python def factory(name, value, self, cls): # Where name - name of the property # value - initial value of the property # self - instance of created object before call __init__ # cls - class object (MyClass) ... ``` of course some of properties could be omitted like this: ```python def factory(name, value, cls): # Where name - name of the property # value - initial value of the property # cls - class object (MyClass) ... ``` As you can see property decorators could be very powerful thing if it will done right ;)

On Thu, Aug 6, 2020 at 6:16 PM <redradist@gmail.com> wrote:
I think a property decorator can be useful, because you consider the simplest case with: ```python class MyClass: @my_property name = arg ``` but consider it can generate the following code: ```python class MyClass: def name(self): ...
def see_name(self): ... ```
Hmmm. I don't really like it, but worst case, you can do this with __set_name__ and mutating the target class. You wouldn't decorate it, just assign a my_property object to the name you want. Alternatively, decorate the class itself with something that does whatever changes you want. ChrisA

On Thu, Aug 06, 2020 at 08:11:50AM -0000, redradist@gmail.com wrote:
I think a property decorator can be useful, because you consider the simplest case with:
We already have `property`, which can be used as a decorator.
```python class MyClass: @my_property name = arg ```
How is it different from name = my_property(arg) which is possible right now, you don't need decorator syntax.
All it will be possible if attribute decorator will have the following signature:
All of it is possible *right now*. You don't need decorator syntax to do any of those examples you show, you just need function calls. You keep showing examples of function calls that do marvellous things, but at no point have you shown any reason why those functions need to be called using decorator syntax instead of ordinary function call syntax. With your decorator suggestion, your marvellous function can only take a single argument: @function # takes a single argument name = arg but with regular function calls, you can pass any combinations of positional and keyword arguments: name = function(arg, more, args, key=value, word=thing) So it seems to me that you want to add special syntax that is *less* powerful than what we already have. Why does this have to use decorator syntax? Please don't give us another list of fantastic things that you can do with function calls, we already know that function calls can do anything. Tell us how the `@function` syntax is better than the `function(arg)` syntax. -- Steven

No it is not possible to have something like this: ```python def function(cls): # Where is cls is Neuron class object pass class Neuron: activation = function(Neuron) ```

On Thu, Aug 06, 2020 at 04:03:39PM -0000, redradist@gmail.com wrote:
No it is not possible to have something like this:
```python def function(cls): # Where is cls is Neuron class object pass
class Neuron: activation = function(Neuron) ```
Correct. And it isn't possible with decorator syntax either: py> def decorator(cls): ... print(cls) ... def inner(func): ... return func ... return inner ... ... py> class Neuron: ... @decorator(Neuron) ... def method(self): ... pass ... Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in Neuron NameError: name 'Neuron' is not defined -- Steven

Maybe I’m lacking context, but I don’t understand the proposal. Can you explain the semantics and syntax you have in mind in more detail? How do you get from the first example (@my_property etc.) to the second (def name, def set_name)? —Guido On Thu, Aug 6, 2020 at 01:13 <redradist@gmail.com> wrote:
I think a property decorator can be useful, because you consider the simplest case with: ```python class MyClass: @my_property name = arg ``` but consider it can generate the following code: ```python class MyClass: def name(self): ...
def see_name(self): ... ``` Or consider the following example: ```python class MyClass: @factory strategy= arg ``` that can will generate: ```python class MyClass: class MyClassStrategy: ...
strategy= MyClassStrategy(arg) ```
All it will be possible if attribute decorator will have the following signature: ```python def factory(name, value, self, cls): # Where name - name of the property # value - initial value of the property # self - instance of created object before call __init__ # cls - class object (MyClass) ... ``` of course some of properties could be omitted like this: ```python def factory(name, value, cls): # Where name - name of the property # value - initial value of the property # cls - class object (MyClass) ... ```
As you can see property decorators could be very powerful thing if it will done right ;) _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@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/MCQBK7... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido (mobile)

Actually in example: ```python class MyClass: @my_property name = arg class MyClass: def name(self): ... def see_name(self): ... ``` I have done mistake ... of course it will not be like this ... What I wanted to show that @my_property could add more complex behavior than just small wrapper in one line For example: ```python # Module a.py class SomeFactory: def __init__(self, cls): self.cls = cls def build_context(self): return context def factory(name, value, self, cls): return SomeFactory(cls) # Module b.py class MyClass: @factory name = arg ``` And so one ... also could be added optionally logging to track each time when somebody read property: ```python # Module b.py class MyClass: @logging # Help to track each time when somebody access property @factory name = arg ``` I see lots of use-cases for property decorators ...

On Thu, Aug 06, 2020 at 04:01:47PM -0000, redradist@gmail.com wrote:
I see lots of use-cases for property decorators ...
We have had property decorators since version Python 2.2 which was 18 years ago. We know that there are many wonderful use-cases for things like this. What you are not explaining is why you can do them with syntax: @function name = value but not name = function(value) -- Steven

Also instead of making all class as dataclass, it would be possible to make only some properties as instance properties: ```python class Client: bank = Bank() @instance name = Name() print(f'Client.bank is {Client.bank}') client = Client() print(f'client.name is {client.name}') ```

Also there is maybe some addition parameter like self: ```python class Neuron: @instance_property activation def __init__(self): # automatically created pass ... def instance_property(name, property, self, *args): # Create property on instance ```
participants (17)
-
André Roberge
-
Chris Angelico
-
Christopher Barker
-
David Mertz
-
Dominik Vilsmeier
-
Ethan Furman
-
Greg Ewing
-
Guido van Rossum
-
Joao S. O. Bueno
-
Jonathan Fine
-
Jonathan Goble
-
Marco Sulla
-
nate lust
-
redradist@gmail.com
-
Ricky Teachey
-
Serhiy Storchaka
-
Steven D'Aprano