On Tue, 3 May 2022 at 03:04, Steven D'Aprano <st...@pearwood.info> 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.

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/

Reply via email to