[Python-ideas] Keyword only argument on function call
Steven D'Aprano
steve at pearwood.info
Sat Sep 8 13:02:46 EDT 2018
On Thu, Sep 06, 2018 at 07:05:57AM -0700, Anders Hovmöller wrote:
> On Thursday, September 6, 2018 at 3:11:46 PM UTC+2, Steven D'Aprano wrote:
[...]
> > But why should I feel bad about failing to
> > use the same names as the functions I call?
>
> Yea, why would you feel bad? If you should have different names, then do.
> Of course.
You are suggesting special syntax which encourages people to name their
local variables the same as the parameters to functions which they call.
That makes a value judgement that it is not just a good thing to match
those names, but that it is *such* a good thing that the language ought
to provide syntax to make it easier.
If we make this judgement that consistency of names is Good, then
naturally *inconsistency* of names is, if not outright Bad, at least
*Less* Good and therefore to be avoided.
If this suggestion is accepted, it's likely that there will be peer
pressure to treat this as more Pythonic (i.e. better quality code) than
the older explicit name=name style, which will quickly become
unPythonic.
See, for example, how quickly people have moved to the implicit
f-strings over the explicit string.format form. Laziness and conciseness
trumps the Zen. Whether this is a good thing or a bad thing, I leave to
people to make up their own mind.
If we believe that this consistency is desirable then maybe this would
be a good thing. Linters could warn when you use "name=spam" instead of
"*, name"; style guides can demand that code always uses this idiom
whenever practical, tutorials and blog posts will encourage it, and the
peer pressure to rename variables to match the called function's
parameters would be a good thing too.
But if consistency for consistency's sake is not generally a good thing,
then we ought not to add such syntax just for conciseness.
> > If some library author names
> > the parameter to a function "a", why should I be encouraged to use
> > that same name *just for the sake of consistency*?
>
> It would encourage library authors to name their parameters well. It
> wouldn't do anything else.
If library authors are choosing bad names for their parameters, how
would this syntax change that practice? If they care so little for their
callers that they choose poorly-named parameters, I doubt this will
change their practice.
But I'm not actually talking about library authors choosing bad names. I
only used "a" as the name following your example. I presumed it was a
stand-in for a more realistic name.
There's no reason to expect that there's only one good name that works
equally well as a formal parameter and as a local argument. Formal
parameters are often more generic, local arguments can be more specific
to the caller's context.
Of course I understand that with this proposal, there's nothing
*forcing* people to use it. But it shifts the *preferred* idiom from
explicit "name=spam" to implicit "*, name" and puts the onus on people
to justify why they aren't naming their local variables the same as the
function parameter, instead of treating "the same name" as just another
name.
[...]
> > My own feeling is that this feature would encourage what I consider a
> > code-smell: function calls requiring large numbers of arguments. Your
> > argument about being concise makes a certain amount of sense if you are
> > frequently making calls like this:
> >
>
> I don't see how that's relevant (or true, but let's stick with relevant).
Let's not :-)
Regarding it being a code-smell:
https://refactoring.guru/smells/long-parameter-list
http://wiki.c2.com/?TooManyParameters
For a defence of long parameter lists, see the first answer here:
http://wiki.c2.com/?LongParameterList
but that active preference for long parameter lists seems to be a very
rare, more common is the view that *at best* long parameter lists is a
necessary evil that needs mitigation.
I think this is an extreme position to take:
https://www.matheus.ro/2018/01/29/clean-code-avoid-many-arguments-functions/
and I certainly wouldn't want to put a hard limit on the number of
parameters allowed. But in general, I think it is unquestionable that
long parameter lists are a code-smell.
It is also relevant in this sense. Large, complex function calls are
undoubtably painful. We have mitigated that pain somewhat by various
means, probably the best of which are named keyword arguments, and
sensible default values. The unintended consequence of this is that it
has reduced the pressure on developers to redesign their code to avoid
long function signatures, leading to more technical debt in the long
run.
Your suggestion would also reduce the pain of functions that require
many arguments. That is certainly good news if the long argument list is
*truly necessary* but it does nothing to reduce the amount of complexity
or technical debt. The unintended consequence is likewise that it
reduces the pressure on developers to avoid designing such functions in
the first place.
This might sound like I am a proponent of hair-shirt programming where
everything is made as painful as possible so as to force people to
program the One True Way. That's not my intention at all. I love my
syntactic sugar as much as the next guy. But I'd rather deal with the
trap of technical debt and excessive complexity by avoiding it in the
first place, not by making it easier to fall into.
The issue I have is that the problem you are solving is *too narrow*: it
singles out a specific special case of "function call is too complex
with too many keyword arguments", namely the one where the arguments are
simple names which duplicate the parameter exactly, but without
actually reducing or mitigating the underlying problems with such code.
(On the contrary, I fear it will *encourage* such code.) So I
believe this feature would add complexity to the language, making
keyword arguments implicit instead of explicit, for very little benefit.
(Not withstanding your statement that 30% of function calls would
benefit. That doesn't match my experience, but we're looking at
different code bases.)
> There are actual APIs that have lots of arguments. GUI toolkits are a great
> example. Another great example is to send a context dict to a template
> engine.
Indeed. And I'm sympathetic that some tasks are inherently complex and
require many arguments. Its a matter of finding a balance between being
able to use them, without encouraging them.
> To get benefit from your syntax, I would need to
> > extract out the arguments into temporary variables:
> > which completely cancels out the "conciseness" argument.
[...]
> > However you look at it, it's longer and less concise if you have to
> > create temporary variables to make use of this feature.
>
>
> Ok. Sure, but that's a straw man....
You claimed the benefit of "conciseness", but that doesn't actually
exist unless your arguments are already local variables named the same
as the parameters of the function you are calling.
Getting those local variables is not always free: sometimes they're
natually part of your function anyway, and then your syntax would be a
genuine win for conciseness. But often they're not, and you have to
either forgo the benefit of your syntax, or add complexity to your
function in order to gain that benefit.
Pointing out that weakness in your argument is not a straw man.
--
Steve
More information about the Python-ideas
mailing list