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/