[Python-ideas] Re: Auto assignment of attributes

2022-05-03 Thread Pablo Alcain
On Tue, May 3, 2022 at 6:36 AM Paul Moore  wrote:

> On Tue, 3 May 2022 at 03:04, Steven D'Aprano  wrote:
> >
> > On Mon, May 02, 2022 at 07:44:14PM +0100, Paul Moore wrote:
> >
> > > I have classes with 20+ parameters (packaging metadata). You can argue
> > > that a dataclass would be better, or some other form of refactoring,
> > > and you may actually be right. But it is a legitimate design for that
> > > use case.
> >
> > Indeed. 20+ parameters is only a code smell, it's not *necessarily*
> > wrong. Sometimes you just need lots of parameters, even if it is ugly.
> >
> > For reference, open() only takes 8, so 20 is a pretty wiffy code smell,
> > but it is what it is.
>
> It's worth noting that dataclasses with lots of attributes by default
> generate constructors that require all of those as parameters. So it's
> a code smell yes, but by that logic so are dataclasses with many
> attributes (unless you write a bunch of custom code). Genuine question
> - what *is* a non-smelly way of writing a dataclass with 24
> attributes?
>
> I've written about 20 variations on this particular class so far, and
> none of them feel "right" to me :-(
>
> > > Of course the real problem is that you often don't want to
> > > *quite* assign the argument unchanged - `self.provides_extras =
> > > set(provides_extras or [])` or `self.requires_python = requires_python
> > > or specifiers.SpecifierSet()` are variations that break the whole
> > > "just assign the argument unchanged" pattern.
> >
> > Indeed. Once we move out of that unchanged assignment pattern, we need
> > to read more carefully rather than skim
> >
> > self._spam = (spam or '').lower().strip()
> >
> > but you can't replace that with auto assignment.
>
> Precisely.
>
> > > As a variation on the issue, which the @ syntax *wouldn't* solve, in
> > > classmethods for classes like this, I often find myself constructing
> > > dictionaries of arguments, copying multiple values from one dict to
> > > another, sometimes with the same sort of subtle variation as above:
> > >
> > > @classmethod
> > > def from_other_args(cls, a, b, c, d):
> > > kw = {}
> > > kw["a"] = a
> > > kw["b"] = b
> > > kw["c"] = c
> > > kw["d"] = d
> > > return cls(**kw)
> >
> > You may find it easier to make a copy of locals() and delete the
> > parameters you don't want, rather than retype them all like that:
> >
> > params = locals().copy()
> > for name in ['cls', 'e', 'g']:
> > del params[name]
> > return cls(**params)
> >
> >
> > > Again, in "real code", not all of these would be copied, or some would
> > > have defaults, etc. The pattern's the same, though - enough args
> > > arecopied to make the idea of marking them with an @ seem attractive.
> >
> > But the @ proposal here won't help. If you mark them with @, won't they
> > be auto-assigned onto cls?
>
> Again, precisely.
>
> My point here is that the @ proposal is, in my experience, useful in
> far fewer situations than people are claiming. What *is* common (again
> in my experience) is variations on a pattern that can be described as
> "lots of repetitive copying of values from one location to another,
> possibly with minor modifications". Having a way of addressing the
> broader problem *might* be of sufficient use to be worth pursuing, and
> it might even be possible to do something useful in a library, not
> needing new syntax.
>

It's a good point. We have been thinking a bit about how to measure the
"usefulness" of the proposal. What we have so far is mainly an intuition
driven by code that we and colleagues developed and a couple of statistics (
https://github.com/quimeyps/analize_autoassign in case anyone reading this
doesn't have the link nearby). Although I think that code analysis can be a
way to find out the usefulness of the proposal, the statistics that we have
so far feel a bit coarse-grained to be honest. So any idea on what would be
good metrics to answer the question of "how ofthen the syntax would be
useful" will be more than welcome!

>
> On the other hand, the @ syntax as proposed *doesn't* address enough
> use cases (for me!) to be worthwhile, especially not if new syntax is
> needed rather than just something like a decorator.
>
> Paul
> ___
> 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/CD3HRBE2Q6WIKOJDE5GCLFVVHMGR42VZ/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
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 

[Python-ideas] Re: Auto assignment of attributes

2022-05-03 Thread Pablo Alcain
On Mon, May 2, 2022 at 11:48 AM Steven D'Aprano  wrote:

> On Mon, May 02, 2022 at 10:34:56AM -0600, Pablo Alcain wrote:
>
> > For what it's worth,
> > the choice of the `@` was because of two different reasons: first,
> because
> > we were inspired by Ruby's syntax (later on learned that CoffeeScript and
> > Crystal had already taken the approach we are proposing) and because the
> > `@` token is already used as an infix for `__matmul__` (
> > https://peps.python.org/pep-0465/). I believe it's the only usage that
> it
> > has, so it probably won't be that confusing to give it this new semantic
> as
> > well.
>
> Did you forget decorators?
>

totally forgot decorators, my bad!


>
> What other languages support this feature, and what syntax do they use?
>

you mean languages other than those two? I haven't found any. In case you
mean the syntax for those two, I know a tiny bit Crystal's. It leverages
the fact that they use `@` for referring to `self`, as in Ruby.

so you would be able to write something like this:

```
class Person
  def initialize(@name : String)
  end

  def greet
print("Hello, ", @name)
  end
end

p = Person.new "Terry"
p.greet
```



>
> Personally, I don't like the idea of introducing syntax which looks
> legal in any function call at all, but is only semantically meaningful
> in methods, and not all methods. Mostly only `__init__`.


Yes, it's a good point. Allowing functions in the wild to use this syntax
would simplify the usage for monkeypatching... but how often would you want
to monkeypatch an `__init__`? and how often would you want to use the
auto-assign outside of the `__init__`? i believe that it's too little. so
in that case, maybe we can make it legal only in all methods. I agree, if
we forego monkeypatching, that semantically it wouldn't be meaningful in
functions; but, in methods, I think that semantically it would make sense
apart from the `__init__`; the thing is that probably it wouldn't be that
useful.


>


> How would this feature work with immutable classes where you want to
> assign attributes to the instance in the `__new__` method?
>
> I fear that this is too magical, too cryptic, for something that people
> only use in a tiny fraction of method. 17% of `__init__` methods is
> probably less than 1% of methods, which means that it is going to be a
> rare and unusual piece of syntax.
>
> Beginners and casual coders (students, scientists, sys admins, etc,
> anyone who dabbles in Python without being immersed in the language) are
> surely going to struggle to recognise where `instance.spam` gets
> assigned, when there is no `self.spam = spam` anywhere in the class or
> its superclasses. There is nothing about "@" that hints that it is an
> assignment.
>
> (Well, I suppose there is that assignment and at-sign both start with A.)
>
> I realise that this will not satisfy those who want to minimize the
> amount of keystrokes, but remembering that code is read perhaps 20-100
> times more than it is written, perhaps we should consider a keyword:
>
> def __init__(self, auto spam:int, eggs:str = ''):
> # spam is automatically bound to self.spam
> self.eggs = eggs.lower()
>
> I dunno... I guess because of that "code is read more than it is
> written" thing, I've never felt that this was a major problem needing
> solving. Sure, every time I've written an __init__ with a bunch of
> `self.spam = spam` bindings, I've felt a tiny pang of "There has to be a
> better way!!!".
>
> But **not once** when I have read that same method later on have I
> regretted that those assignments are explicitly written out, or wished
> that they were implicit and invisible.
>
> Oh, by the way, if *all* of the parameters are to be bound:
>
> def __init__(self, spam, eggs, cheese, aardvark):
> vars(self).update(locals())
> del self.self
>
> Still less magical and more explicit than this auto-assignment proposal.
>
>
>
> --
> 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/C5I33AB2WLW77I77QAJFKZFBJOVNJ7RR/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
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/JOFVYZG5CSV4C4GVE3QCAKBAENAYROMO/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Auto assignment of attributes

2022-05-02 Thread Pablo Alcain
On Mon, May 2, 2022 at 7:21 AM Steven D'Aprano  wrote:

> On Sun, May 01, 2022 at 06:22:08PM -0700, Devin Jeanpierre wrote:
>
> > Is it unreasonable to instead suggest generalizing the assignment target
> > for parameters? For example, if parameter assignment happened left to
> > right, and allowed more than just variables, then one could do:
> >
> > def __init__(self, self.x, self.y): pass
>
> What would this do?
>
> def __init__(self, spam.x, eggs.y): pass
>
> Would it try to assign to variables spam and eggs in the surrounding
> scopes?
>
> How about this?
>
> def __init__(self, x, x.y): pass
>

Yes, I agree. I don't think that the syntax is unreasonable, but it looks
like it would be putting `self` at the same "level" of all the other
possible parameters and could lead to this kind of confusion.

What _might_ be a possibility (I'm not advocating in favor of it) is, like
ruby does, to also add the `@x` as syntactic sugar for `self.x` in the body
of the methods. This way the `@x` in the signature would be consistent, but
I believe it can conflict conceptually with the "explicit self" philosophy.


>
>
> --
> 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/WDRZ7QYQWXCL3QTV4YVIL2YUAS4DNK7I/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
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/LKVUSGMXYWZHBK432UHL2ACVZOWNWH5P/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Auto assignment of attributes

2022-05-02 Thread Pablo Alcain
On Sun, May 1, 2022 at 10:35 AM Ethan Furman  wrote:

> On 5/1/22 00:21, Christopher Barker wrote:
>  > On Sat, Apr 30, 2022 at 2:17 PM Pablo Alcain wrote:
>
>
>  >> It shows that out of 20k analyzed classes in the selected libraries
> (including black,
>  >> pandas, numpy, etc), ~17% of them could benefit from the usage of
> auto-assign syntax.
>  >
>  > I only read English, and haven't studied the coe, so I don't know how
> that works, but
>  > assuming it's accurately testing for the simple cases that
> auto-assigning could work for;
>  >
>  > That's not that much actually --  for approx every six-parameter
> function, one of them
>  > could be auto-assigned.or for every six functions, one could make good
> use of auto-
>  > assignment (and maybe be a dataclass?)
>
> I think you place too much emphasis on dataclasses -- none of my projects
> use them, nor could they.
>
> Going through a one of my smaller projects, this is what I found:
>
> - number of `__init__`s: 11
> - number of total params (not counting self): 25
> - number of those params assigned as-is: 19
> - number of `__init__`s where all are assigned as-is: 6
> - number of non-`__init__`s where this would useful: 0
>
>
>  > And I'm not trying to be a Negative Nelly here -- I honestly don't
> know, I actually
>  > expected it to be higher than 17% -- but in any case, I think it should
> be higher than
>  > 17% to make it worth a syntax addition.
>
> 17% is a massive amount of code.
>
>  > But pandas and numpy may not be the least bit representative [...]?
>
> This would not be the first time Python was improved to help the
> scientific community.
>
> My own thoughts about the proposal:  It seems interesting, and assigning
> as-is arguments is a chore -- but I'm not sure
> using up a token to help only one method per class is a good trade.
>

Yes, I agree that the cost/benefit should be analyzed. For what it's worth,
the choice of the `@` was because of two different reasons: first, because
we were inspired by Ruby's syntax (later on learned that CoffeeScript and
Crystal had already taken the approach we are proposing) and because the
`@` token is already used as an infix for `__matmul__` (
https://peps.python.org/pep-0465/). I believe it's the only usage that it
has, so it probably won't be that confusing to give it this new semantic as
well. All of this, I believe, mitigate the "using up a token", but it's not
enough to make it a clear decision, so I 100% agree with your concern.



>
> --
> ~Ethan~
> ___
> 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/2GR5G67IKJZDSFU4QYJQF7R4BCZUZPMJ/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
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/V4TF6WRERLQBOQ72BGWHYAXCYX6MCT6J/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Auto assignment of attributes

2022-04-30 Thread Pablo Alcain
On Sat, Apr 23, 2022, 1:11 PM Christopher Barker 
wrote:

> On Sat, Apr 23, 2022 at 10:53 AM Pablo Alcain 
> wrote:
>
>> Overall, I think that not all Classes can be thought of as Dataclasses
>> and, even though dataclasses solutions have their merits, they probably
>> cannot be extended to most of the other classes.
>>
>
> Absolutely. However, this is not an "all Classes" question.
>
> I don't think of dataclasses as "mutable namedtuples with defaults" at all.
>

Although I agree that dataclasses have definitely grown beyond this scope,
the definition of “mutable namedtuples with defaults” come from the
original PEP (https://peps.python.org/pep-0557/#abstract). The main point
here is that there are several usecases for classes that do not fit
conceptually the “dataclass” goal.


> But do think they are for classes that are primarily about storing a
> defined set of data.
>
> I make heavy use of them for this, when I am adding quite a bit of
> ucntionatily, but their core function is still to store a collection of
> data. To put it less abstractly:
>
> Dataclasses are good for classes in which the collection of fields is a
> primary focus -- so the auto-generated __init__, __eq__ etc are appropriate.
>
> It's kind of a recursive definition: dataclasses work well for those
> things that data classes' auto generated methods work well for :-)
>
> If, indeed, you need a lot of custom behavior for teh __init__, and
> __eq__, and ... then datclasses are not for you.
>

I agree 100%. This proposal, at its core, is not related with dataclasses.
There are some cases in which dataclasses are the solution, but there are
many many times in which you will want to use just classes.

>
> And the current Python class system is great for fully customized
> behaviour. It's quite purposeful that parameters of the __init__ have no
> special behavior, and that "self" is explicit -- it gives you full
> flexibility, and everything is explicit. That's a good thing.
>
> But, of course, the reason this proposal is on the table (and it's not the
> first time by any means) is that it's a common pattern to assign (at least
> some of) the __init__ parameters to instance attributes as is.
>
> So we have two extremes -- on one hand:
>
> A) Most __init__ params are assigned as instance attributes as is, and
> these are primarily needed for __eq__ and __repr__
>
> and on the other extreme:
>
> B) Most __init__ params need specialized behavior, and are quite distinct
> from what's needed by __eq__ and __repr__
>
> (A) is, of course, the entire point of dataclasses, so that's covered.
>
> (B) is well covered by the current, you-need-to-specify-everything
> approach.
>

I don’t see B as a “extreme approach”. I think that comparing python
classes with the specific dataclass is not helpful. The B scenario is
simply the general case for class usage. Scenario A, I agree, is a very
common one and fortunately we have dataclasses for them.


> So the question is -- how common is it that you have code that's far
> enough toward the (A) extreme as far as __init__ params being instance
> attributes that we want special syntax, when we don't want most of the
> __eq__ and __repr__ behaviour.
>

I agree that this is the main question. For what it’s worth, a quick grep
on the stdlib (it’s an overestimation) provides:

$ grep -Ie "self\.\(\w\+\) = \1" -r cpython/Lib | wc
2095

I did the same in two libraries that I use regularly: pandas and
scikit-learn:

$ grep -Ie "self\.\(\w\+\) = \1" -r sklearn | wc -l
1786

$ grep -Ie "self\.\(\w\+\) = \1" -r pandas | wc -l
650

That’s a total of ~4.5k lines of code (again, this is an overestimation,
but it can give us an idea of the ballpark estimate)

For a better and more fine-grained analysis, Quimey wrote this small
library (https://github.com/quimeyps/analize_autoassign) that uses the
Abstract Syntax Tree to analyze a bunch of libraries and identify when the
“autoassign” could work. It shows that out of 20k analyzed classes in the
selected libraries (including black, pandas, numpy, etc), ~17% of them
could benefit from the usage of auto-assign syntax.

So it looks like the isolated pattern of `self. = `
is used a lot. I don’t think that moving all of these cases to dataclasses
can provide a meaningful solution. When I take a look at these numbers (and
reflect in my own experience and my colleagues) it looks like there is a
use case for this feature. And this syntax modification looks small and
kind of clean, not adding any boilerplate. But, obviously, it entails a
further of discussion whether it makes sense to add new syntax for this,
considering the maintenance that it implies.


> In my experience, not all that much -- my code tends to be on one extreme
> or the

[Python-ideas] Re: Auto assignment of attributes

2022-04-23 Thread Pablo Alcain
On Thu, Apr 21, 2022 at 7:33 PM Josh Rosenberg <
shadowranger+pythonid...@gmail.com> wrote:

>
> On Wed, Apr 20, 2022 at 3:31 PM Pablo Alcain 
> wrote:
>
>>
>> About dataclasses, the point that Chris mentions, I think that they are
>> in a different scope from this, since they do much more stuff. But, beyond
>> this, a solution on the dataclass style would face a similar scenario:
>> since the `__init__` is autogenerated, you would also be in a tight spot in
>> the situation of "how would I bind only one of the items?". Again, now I'm
>> talking about my experience, but I think that it's very hard to think that
>> we could replace "classes" with "dataclasses" altogether. Here's an example
>> of one of the (unexpected for me) things that happen when you try to do
>> inheritance on dataclasses: https://peps.python.org/pep-0557/#inheritance
>> .
>>
>> dataclasses, by default, do four things with the annotated fields defined
> in the class:
>
> 1. Generate a __init__
> 2. Generate a reasonable __repr__
> 3. Generate a reasonable __eq__
> 4. Automatically support destructuring with match statements
>

This is very interesting. I use dataclasses quite a lot tbh, but I do think
that the purpose is different: the  `__repr__` and `__eq__` they generate,
for example, are reasonable when you consider that the classes are "mutable
namedtuples with defaults". the effective use of dataclasses indeed goes
beyond the "mutable namedtuples" thing, but as this happens then the
"reasonability" of the default `__repr__` and `__eq__` also starts to fade.
as a small experience token: in one point in time, I ended up having a
`dataclass` that reimplemented both `__init__` (through `__post_init__`)
and `__repr__`. Then I realized that I probably didn't want a dataclass to
begin with.


>
>

> And you can independently disable any/all of them with arguments to the
> decorator. They *can* do much more, but I find it pretty unusual to *ever*
> write a class that I wouldn't want most of those for. The __init__ it
> generates is essentially automatically writing the boilerplate you're
> trying to avoid, so it seems entirely reasonable to consider this the same
> scope.
>
> As for "how would I bind only one/some of the items?", dataclasses already
> support this with dataclasses.InitVar and a custom __post_init__ method; so:
>
> class MyClass:
>
> def __init__(self, @a, @b, c):
>
> ... do something with c that doesn't just assign it as self.c...
>
> where you directly move values from the a and b arguments to self.a and
> self.b, but use c for some other purpose, is spelled (using typing.Any as a
> placeholder annotation when there's no better annotation to use):
>
> @dataclass
> class MyClass:
> a: Any
> b: Any
> c: InitVar[Any]
> def __post_init__(self, c):
> ... do something with c that doesn't just assign it as self.c;
> self.a and self.b already exist ...
>
> The only name repeated is c (because you're not doing trivial assignment
> with it), and it's perfectly readable. I'm really not seeing how this is
> such an unwieldy solution that it's worth adding dedicated syntax to avoid
> a pretty trivial level of boilerplate that is already avoidable with
> dataclasses anyway.
>

I think that in some scenarios it can be done, but it doesn't look very
clean: namely with the explicit declaration of `InitVar` and the usage of
the `__post_init__`. It looks like this case in which you don't like the
autogenerated solution and patch it to reflect your actual goal. It's ok,
but it's also going to lead towards harder to mantain and interpret code.


>
> -Josh
>

Overall, I think that not all Classes can be thought of as Dataclasses and,
even though dataclasses solutions have their merits, they probably cannot
be extended to most of the other classes.

Pablo
___
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/B6Q4LFCETYYY6HOR7UT4ZC5MQ73SJ3YA/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Auto assignment of attributes

2022-04-21 Thread Pablo Alcain
Hey Joao! For what it's worth, I'm not a big fan of the proposal to be
honest, for the reasons I have already mentioned. I'm not heavily against
it, but I would most likely not use it. Nevertheless, I believe it would
need a PEP since it probably can change substantially the way Python code
is being written.

I think that discussion can probably belong to a specific thread with the
proposal with your questions summary there so everyone can contribute to
the implementation that, clearly, has some interesting points that it would
be better if we could discuss in detail.

I would very much like for us to evaluate, in this thread, the original
proposal we sent, regarding if anyone else thinks it would make sense to
add a new syntax for the binding of attributes.

Pablo
___
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/7FKGRN2NQOZJK5MPVCYGDHDM6L2VCA4D/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Auto assignment of attributes

2022-04-20 Thread Pablo Alcain
Regarding the usage of a decorator to do the auto-assignment, I think that
it has an issue regarding how to select a subset of the variables that you
would be setting. In the general case, you can probably get away with
calling `autoassign`. But, for example, if you want to set a but not b,
you'd probably have to use a string as the identifier of the parameters
that you want to assign:

```
class MyKlass:
@autoassign('a')
def __init__(self, a, b):
print(b)

```

This, in my perspective, brings two things: the first one is that you'd be
repeating everywhere the list of names, so for example doing refactors like
changing a variable name would be a bit error-prone: If you change the
variable from `a` to `my_var_name`, you'd have to also change the list in
the autoassign. It's not a lot, but it can induce some errors because of
the repetition. On the other hand, I guess it would be a bit hard for IDEs
and static checkers to follow this execution path. I know that I'm only one
data point, but for what it's worth, I was very excited with the idea but
this prevented me from actually implementing this solution on a day-to-day
basis: it felt a bit fragile and induced me to some errors.

About dataclasses, the point that Chris mentions, I think that they are in
a different scope from this, since they do much more stuff. But, beyond
this, a solution on the dataclass style would face a similar scenario:
since the `__init__` is autogenerated, you would also be in a tight spot in
the situation of "how would I bind only one of the items?". Again, now I'm
talking about my experience, but I think that it's very hard to think that
we could replace "classes" with "dataclasses" altogether. Here's an example
of one of the (unexpected for me) things that happen when you try to do
inheritance on dataclasses: https://peps.python.org/pep-0557/#inheritance.

Overall, I think that it's hard to think about a solution to this problem
that is clean and robust without adding new syntax with it. I would like to
hear your thoughts on this (and everyone else's of course!)

Cheers,
Pablo

On Mon, Apr 18, 2022 at 9:55 PM Christopher Barker 
wrote:

> On Mon, Apr 18, 2022 at 4:24 PM Joao S. O. Bueno 
> wrote:
>
>> I for one am all for the inclusion of a decorator targeting either the
>> __init__ method
>> or the class itself to perform this binding of known arguments to
>> instance attributes
>> prior to entering __init__. It could live either in functools or
>> dataclasses itself.
>>
>
> Isn’t this what dataclasses already accomplish? I understand that it’s the
> reverse— with a dataclass, you specify the fields, and the __init__ is
> generated, whereas this proposal is ttt be at you’d write an __init__, and
> the attributes would be set — but other than taste, is there a practical
> difference?
>
> -CHB
>
>
>> On Sat, Apr 16, 2022 at 5:49 PM Pablo Alcain 
>> wrote:
>>
>>> The problem of assigning init arguments as attributes has appeared
>>> several times in the past (
>>> https://mail.python.org/archives/list/python-ideas@python.org/message/VLI3DOFA5VWMGJMJGRDC7JZTRKEPPZNU/
>>> was the most recent we could find) and is already handled in dataclasses.
>>>
>>> Lately, discussing this topic with a friend, we thought that using a
>>> specific token could be a possible approach, so you could do:
>>>
>>> class MyClass:
>>>
>>> def __init__(self, @a, @b, c):
>>>
>>> pass
>>>
>>> and it would be analogous to doing:
>>>
>>> class MyClass:
>>>
>>> def __init__(self, a, b, c):
>>>
>>> self.a = a
>>>
>>> self.b = b
>>>
>>> Then, you would instantiate the class as usual, and the variables tagged
>>> with `@` would be bound to the object:
>>>
>>> >>> objekt = MyClass(2, 3, 4)
>>>
>>> >>> print(objekt.b)
>>>
>>> 3
>>>
>>> >>> print(objekt.c)
>>>
>>> AttributeError: 'MyClass' object has no attribute 'c'
>>>
>>>
>>> We have a working implementation here if anyone wants to take a look at:
>>> https://github.com/pabloalcain/cpython/tree/feature/auto_attribute.
>>> Keep in mind that we have limited knowledge about how to modify cpython
>>> itself, and which would the best places be to do the modifications, so it's
>>> more than likely that some design decisions aren't very sound (
>>> https://devguide.python.org/grammar/ and
>>> https://devguide.python.org/parser/ were incredibly helpful).
>>>
>>> Besides the implementation, we would like to 

[Python-ideas] Auto assignment of attributes

2022-04-16 Thread Pablo Alcain
The problem of assigning init arguments as attributes has appeared several
times in the past (
https://mail.python.org/archives/list/python-ideas@python.org/message/VLI3DOFA5VWMGJMJGRDC7JZTRKEPPZNU/
was the most recent we could find) and is already handled in dataclasses.

Lately, discussing this topic with a friend, we thought that using a
specific token could be a possible approach, so you could do:

class MyClass:

def __init__(self, @a, @b, c):

pass

and it would be analogous to doing:

class MyClass:

def __init__(self, a, b, c):

self.a = a

self.b = b

Then, you would instantiate the class as usual, and the variables tagged
with `@` would be bound to the object:

>>> objekt = MyClass(2, 3, 4)

>>> print(objekt.b)

3

>>> print(objekt.c)

AttributeError: 'MyClass' object has no attribute 'c'


We have a working implementation here if anyone wants to take a look at:
https://github.com/pabloalcain/cpython/tree/feature/auto_attribute. Keep in
mind that we have limited knowledge about how to modify cpython itself, and
which would the best places be to do the modifications, so it's more than
likely that some design decisions aren't very sound (
https://devguide.python.org/grammar/ and https://devguide.python.org/parser/
were incredibly helpful).

Besides the implementation, we would like to know what the community thinks
on whether this might have any value. While developing this, we realized
that Crystal already has this feature (eg
https://github.com/askn/crystal-by-example/blob/master/struct/struct.cr)
with the same syntax; which is kind of expected, considering it's syntax is
based on Ruby.


Random collection of thoughts:

1. If auto-assignment made sense in general, one of the reasons we went for
this rather than the decorator approach is that we wouldn't like to have a
list of strings that can vary decoupled from the actual argument name.

2. The current implementation of `@` works for any function, not only init.
We don't know if this would actually be a desirable feature.

3. It also works with any function in the wild. This mostly allows for
monkey-patching to work out of the box:

>>> class Klass:

... def __init__(self):

... pass

...

>>> def add_parameter(k, @p):

... pass

...

>>> Klass.add_parameter = add_parameter

>>> objekt = Klass()

>>> print(objekt.p)

Traceback (most recent call last):

  File "", line 1, in 

AttributeError: 'Klass' object has no attribute 'p'

>>> objekt.add_parameter(11)

>>> print(objekt.p)

11

Again, we are not sure if this is desirable, but it's what made most sense
for us at the moment.

4. Adding the `@` token to the argument doesn’t remove the variable from
the function/method scope, so this would be perfectly valid:

>>> def my_function(k, @parameter):

... print(parameter)

>>> my_function(objekt, 4)

4

>>> k.parameter

4



5. We didn’t implement it for lambda functions.

Cheers,

Pablo and Quimey
___
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/SCXHEWCHBJN3A7DPGGPPFLSTMBLLAOTX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] asyncio: return from multiple coroutines

2020-06-22 Thread Pablo Alcain
Hey everyone. I have been looking into asyncio lately, and even though I
have had my fair share of work, I still have some of it very shaky, so
first of all forgive me if what I am saying here is already implemented and
I totally missed it (so far, it looks *really* likely).

Basically this is the situation: I have an application that listens on two
websockets through the async library https://websockets.readthedocs.io/ and
I have to perform the same function on the result, no matter where the
message came from. I understand that I can create two coroutines that call
the same function, but it would be much cleaner (because of implementation
issues) if I can simply create a coroutine that yields the result of
whichever connection arrives first.

I have implemented a rather cumbersome solution with async Queues (as I
would do in threading), in which each connection puts its message in a
queue and an adapter class awaits the first element of the queue on
"receive". Here I attach a pastebin with the minimal working example:
https://pastebin.com/BzaxRbtF

However, it looks like a more async-friendly solution should exist,
something like

```
async def _start():
msg1 = recv("Messager 1", sleep_time=1)
msg2 = recv("Messager 2", sleep_time=2)
while True:
result = await asyncio.on_first_return(msg1, msg2)
print(result)
```

(I understand that this implementation would not work because the event
loop doesn't know that it is "the same task repeated", but it's just to
tell you the general idea)

Again, it's quite likely I am not seeing something obvious, but I didn't
know where else to ask.

Thank you very much,
Pablo
___
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/XBR5QPXRBCCJELDVEWMKRBPTNG4SJM64/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: JSON Serializing UUID objects

2020-06-10 Thread Pablo Alcain
I don't know how or even whether this would be possible ootb. On one side,
I do really like the idea; on the other hand, it kind of seems like going
down a bumpy road (as you said, datetimes? filepaths?urls?). And the
de-serialization would not be easy.

What if we added a function call for the serialization, something like
json.dumps(object, method=str) (don't know if that is an option at the
moment)

On Wed, Jun 10, 2020 at 9:19 AM J. Pic  wrote:

> Hi all,
>
> This is a proposal to enable uuid objects serialization / deserialization
> by the json module out of the box.
>
> UUID objects cast to string:
>
> >>> example = uuid.uuid4()
> >>> str(example)
> 'b8bcbfaa-d54f-4f33-9d7e-c91e38bb1b63'
>
> The can be casted from string:
>
> >>> example == uuid.UUID(str(example))
> True
>
> But are not serializable out of the box:
>
> >>> json.dumps(example)
> Traceback (most recent call last):
>   File "", line 1, in 
>   File "/usr/lib/python3.8/json/__init__.py", line 231, in dumps
> return _default_encoder.encode(obj)
>   File "/usr/lib/python3.8/json/encoder.py", line 199, in encode
> chunks = self.iterencode(o, _one_shot=True)
>   File "/usr/lib/python3.8/json/encoder.py", line 257, in iterencode
> return _iterencode(o, 0)
>   File "/usr/lib/python3.8/json/encoder.py", line 179, in default
> raise TypeError(f'Object of type {o.__class__.__name__} '
> TypeError: Object of type UUID is not JSON serializable
>
> Wouldn't it be pythonically possible to make this work out of the box,
> without going through the string typecasting ?
>
> If that discussion goes well perhaps we can also talk about datetimes ...
> I know there's nothing about datetime formats in the json specification,
> that users are free to choose, but could we choose a standard format by
> default that would just work for people who don't care about the format
> they want.
>
> Thank you in advance for your replies
>
> Have a great day
>
> --
> ∞
> ___
> 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/W23G6CWWXPCB3L5M2UGGLOEALO5WN4IN/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
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/NFYCQGEQ7R7MHCNVGP5WXHXRIJN7LN52/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Auto-assign attributes from __init__ arguments

2020-05-07 Thread Pablo Alcain
Hello everyone, I am Pablo from Argentina! This is my first email here, so
just let me know if I am missing anything that is of use in this list, such
as presenting myself. As for this topic in particular:

Although I might use it a lot (more than I would like to admit), I don't
like this feature. First of all, I think it favors not-very-pretty code,
effectively reducing the cost you pay for writing too-many-argument
functions. It'd also obfuscate the code, and here I would like to quote the
Zen of Python "explicit is better than implicit".

It looks kind of similar (I know it has nothing to do in practice, but I
think in mindset) to creating a dictionary of parameters that you pass to
the function in order to avoid writing multiple args. If you are thinking
of doing that, maybe the problem is that you are using a wrong design, and
a programming language should "punish" it somehow.



On Wed, May 6, 2020 at 6:55 PM Lewis Ball  wrote:

> Joao S. O. Bueno wrote:
> > Here -  with the current inspect.Signature, it is straightforward
> > to get a decorator that can do that covering most, if not all,
> > corner cases, and even adding some extra functionality:
> > https://gist.github.com/jsbueno/f689a181d50384f627b43b9b2aabe4f2
> >
> > from inspect import signature, Parameter
> > from functools import wraps, partial
> >
> > def autoassign(func=None, *, expand_kwargs=False):
> >
> > if not func:
> > return partial(autoassign, expand_kwargs=expand_kwargs)
> > sig = signature(func)
> > @wraps(func)
> > def wrapper(*args, **kwargs):
> > instance = args[0]
> > bound_args = sig.bind(*args, **kwargs)
> > bound_args.apply_defaults()
> > for i, (key, value) in enumerate(bound_args.arguments.items()):
> > if i == 0 or sig.parameters[key].kind ==
> Parameter.POSITIONAL_ONLY:
> > continue
> > if expand_kwargs and sig.parameters[key].kind ==
> > Parameter.VAR_KEYWORD:
> > for kwkey, kwvalue in value.items():
> > setattr(instance, kwkey, kwvalue)
> > continue
> > setattr(instance, key, value)
> > return func(*args, **kwargs)
> > return wrapper
> >
> > """
> > class A:
> > @autoassign
> > def __init__(self, a, b, c=3):
> > pass
> >
> > a = A(1, 2)
> > assert a.a == 1 and a.b == 2 and a.c == 3
> > """
>
> Is there a good reason to exclude positional only args from this? I
> imagine if you are passing them to init you still want them to be treated
> internally in the same way as the other args.
>
> > Could we put this into the standard library, so that IDEs and linters are
> > programmed to recognise it?
>
> I agree, without this being recognised by linters/IDEs any attrs will show
> with ugly warnings which would stop anyone from using it.
> ___
> 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/IMBONGILTSVKQ6JXYU3PEEN5XY4ICD5K/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
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/C54WVBCSL5ID4XD5MYGLOSK6V24EYHWN/
Code of Conduct: http://python.org/psf/codeofconduct/