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.
> In that sort of case, 20+ lines of assignments in the
> constructor *are* actually rather unreadable, not just a pain to
> write.
I don't know. Its pretty easy to skim lines when reading, especially
when they follow a pattern:
self.spam = spam
self.eggs = eggs
self.cheese = cheese
self.aardvark = aardvark
self.hovercraft = hovercraft
self.grumpy = grumpy
self.dopey = dopey
self.doc = doc
self.happy = happy
self.bashful = bashful
self.sneezy = sneezy
self.sleepy = sleepy
self.foo = foo
self.bar = bar
self.baz = baz
self.major = major
self.minor = minor
self.minimus = minimus
self.quantum = quantum
self.aether = aether
self.phlogiston = phlogiston
Oh that was painful to write!
But I only needed to write it once, and I bet that 99% of people reading
it will just skim down the list rather than read each line in full.
To be fair, having written it once, manual refactoring may require me to
rewrite it again, or at least edit it. In early development, sometimes
the parameters are in rapid flux, and that's really annoying.
But that's just a minor period of experimental coding, not an on-going
maintenance issue.
> 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.
> 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?
--
Steve
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/TPRCJTZJRHVUVSHHPDFXN3O2LDWGZRRB/
Code of Conduct: http://python.org/psf/codeofconduct/