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

Reply via email to