On May 17, 2017 04:16, "Michel Desmoulin" email@example.com wrote:
Le 17/05/2017 à 07:22, Guido van Rossum a écrit :
On Tue, May 16, 2017 at 8:14 PM, Juancarlo Añez <firstname.lastname@example.org mailto:email@example.com> wrote:
What I like about attrs is: * The class level declaration of instance attributes * That the reasonable *init*, *repr*, and *eq* are generated
OK, the former should be doable using PEP 526 (the type is stored in __annotations__ and the default in the class dict given to the metaclass), while the latter should be doable using a standard metaclass -- assuming we can agree on what the "reasonable" __init__, __repr__ and __eq__ should do.
I don’t like the excessive wordiness in attrs,
Really? @attr.s is wordy? :-) I think it's deadly cute. (The only library I've ever seen that did something worse was "monocle" which used @_o.)
import attr @attr.s
... class Point: ... x = attr.ib(default=42) ... y = attr.ib(default=attr.Factory(list))
Is pretty wordy compared to something like another language would do such as:
class Point: int x = 42 list y = 
Now I get that:
- Python already has a similar syntax creating class attributes. - You can't put mutable objects here. - attr does more since it generates dunder methods.
But having an import, a decorator and verbose calls to attr.ib does not feel like idiomatic Python at all. Python is an elegant and expressive language. This is none of the above. Also Python is beginner friendly. Now OPP is already hard to teach to my students, but if I have to add this to the mix, I will just have to tell them to copy / paste it blindly for a long time before I can get to the point they can understand what it does.
We should be able to find a middle ground.
First, if we have something LIKE attr, should it need an import? Basic data structures may not require an import to work. async/await are way better than import @asyncio.coroutine.
Secondly, while I really, really, really want this feature, I think we should not rush it.
Some ideas have to be explored.
Adding keywords for it ? I know adding a keyword is the worst thing one can suggest on this list ever. But it has to be mentioned because most other languages do it this way.
class Point: instancevar x = 42 instancevar y = lazy  # we add a debate about this a few months ago
Adding a special syntax for it ? ruby has something similar.
class Point: @x = 42 @@y = list
Upgrading the class constructor? It does not address the mutablility issue though.
class Point(x=42, y=)
class Point(metaclass=autoclass(x=42, y=lazy )): pass
@args(x=42) @factory_args(y=list) @autodunder() class Point: pass
@autoclass( x=42 y=autoclass.lazy(list) ) class Point: pass
Just adding attrs, which is a workaround to a missing feature in Python, as a boiler plate and calling it a day seems unwise.
Don't get me wrong, I like attrs, I like asyncio and I like the whole battery included concept. But we lived without it until now, so let's not go too fast on this.
What about an attribute-level decorator-like syntax, like:
class Point: @instattr x = 42 @instattr @lazy y = 
class Point: @instattr: x = 42 @instattr: @lazy: y = 
This would have the benefit of a keyword-like syntax without actually needing a new keyword.
The question is how such a system would work in a general manner. Of course these aren't decorators, something new would be needed. I see two main approaches.
1. These functions are called both at class creation and initialization time with arguments that let it decide what to do. So perhaps it is given whatever is on the right side of the "=", the class, and the class instance (which is None at class creation time). Perhaps it is given the variable name as a string, or perhaps Python magically adds the name to the namespace whenever the function returns. Alternatively, this could be a class and there are two dunder methods that are called at class creation time and class initialization time.
2. These are called at attribute access time. Python sets up the attribute as a special property, and whenever the attribute is accessed the function is given arguments that allow it to infer what is going on. It then controls if and how the variable is accessed. Alternatively, this could be a class and there are dunder methods called at various times.
The second approach would be more flexible, while the first approach would require less work for developers for basic tasks. The two approaches are not mutually-exclusive, either, especially if a dunder method-based approach is used.
I know that strictly speaking the property-based approach could be implemented in the function-based approach, but that would be a lot more work.