Implicit keyword arguments for Python
Python functions can use both positional and keyword arguments; the latter provide a certain level of documentation for an argument and its meaning, while allowing them to be given in any order in a call. But it is often the case that the name of the local variable to be passed is the same as the keyword, which can lead to overly repetitive argument lists, at least in some eyes. A recent proposal to shorten the syntax for calls with these duplicate names seems to be gaining some steam—a Python Enhancement Proposal (PEP) is forthcoming—though there are some who find it to be an unnecessary and unwelcome complication for the language.
Parameters and arguments
The parameter list of a Python function describes the names of its parameters; those parameters are matched up with the arguments that get passed in a call to the function. For example:
def func(a, b, c=3, d=None): # definition with four parameters
pass
func(1, b=42, c=9, d=6) # a call with four arguments
But it is not infrequent that calls are made where the argument and
parameter have the same name, which leads to some duplication in the call:
func(a=a, b=b, c=c, d=d)
For parameters with short names, such as these, the duplication is probably
not really significant, but longer parameter names change that picture:
func2(visibility=visibility, frobnification_level=frobnification_level)
In those cases, the duplication just adds a lot extra noise, so Joshua
Bambrick suggested adding
some syntactic sugar to avoid the problem; his goal is to promote the use
of keyword arguments, which he believes are underused in part because of
this visual noise.
His original suggestion was as follows:
# instead of this:
func2(visibility=visibility, frobnification_level=frobnification_level)
# this could be used:
func2(=visibility, =frobnification_level)
He had a long list of benefits, relating several of them to entries in
PEP 20 ("The Zen of
Python");
the overall idea is to increase the readability while reducing verbosity.
The change would be backward compatible, because the new construct is a
syntax error in today's Python.
Nir Schulman thought that it made more sense to put the "=" at the end of the parameter name; it may be easier to implement that way and it is analogous to the f-string f'{var=}' construct.
func2(visibility=, frobnification_level=)
Guido van Rossum agreed
with that second syntax
and was willing to be the core-developer sponsor of a PEP if someone wanted
to write one. Bambrick and several others quickly volunteered to work on
it.
There were several commenters who were in favor of the idea and
the "postfix" version, with the = after the parameter name,
proved to be more popular, so it seems likely to be the syntax proposed in
the PEP. But "Miraculixx" strongly
disagreed; it will confuse beginners, they said, who are already
somewhat confused by keyword arguments. They had their own list of
quarrels
with the idea (with nods to PEP 20 as well), many of which come
down to personal preference (as, of course, do the benefits Bambrick
listed). But Miraculixx also pointed out that it could lead to a somewhat
subtle and possibly hard-to-find error: "renaming the variable in the
calling context will break the code and it is not obvious to fix
".
Paul Moore agreed
with those arguments, noting that he would not use the feature himself, nor
allow it in projects he maintains. He said that he can live with it if
the feature gets added, but: "Python does seem to be gaining features
I'm preferring not to use much more than features I'm enthusiastic about,
these days :(
"
Numbers
Chris Angelico, who was one of those who volunteered to help with the PEP, thought that some of Miraculixx's complaints were not entirely reasonable. Angelico also did some research on the prevalence of "var=var" in the Python standard library; he found 3858 examples, which suggests to him that there is a real need for the feature. Likewise, Hugo van Kemenade found many instances of the pattern in other Python code bases. Angelico said that the short "x=x" examples do not really do justice to the idea; his search found 525 places where the identifiers were ten or more characters in length (310 if the unit tests are eliminated):
And I would absolutely argue that there's clarity to be gained here:
ElementTree(element).write(stream, encoding,
xml_declaration=xml_declaration,
default_namespace=default_namespace,
method=method,
short_empty_elements=short_empty_elements)
# vs #
ElementTree(element).write(stream, encoding,
xml_declaration=,
default_namespace=,
method=,
short_empty_elements=)
He further argued that brevity, in and of itself, is not really the goal; instead, the feature will help people spot problems:
When xml_declaration= is the norm, it's obvious that xml_declaration=html_declaration must be intentional and cannot possibly be a transcription error (okay, that particular example probably wouldn't happen, but you get the idea).
Inevitably, some bikeshedding over naming took place. Tamás Hadházy asked:
"what this syntactic sugar should be called?
" Ideas ranged from
"implicit named arguments" through "abbreviated keyword arguments" and
"elided keyword arguments" to "shorthand-keyword-arguments" (and others).
Bambrick noted
that other languages call it "punning", though the reasons
for that may be a little obscure. There was no real consensus on a
name, though Bambrick did use "punning" in an example pull
request (PR) with a massive diff
that modifies the
standard library to use the new syntax.
The conversation soon wandered back to the feature itself. James Webber wondered
if the perceived need for it was actually due to "bad ergonomics
" of
various sorts in
function definitions:
Maybe I've converted too many things to be keyword-only, or I've ordered my arguments in a silly way (like, put uncommonly-specified arguments too early). Syntactic sugar covers up the mess a little but the code itself could be improved.
Moore agreed;
"this feels like it's helping to make functions with lots of keyword
arguments more tolerable, but maybe there's an underlying problem where a
better API design would avoid the need for lots of keyword arguments in the
first place?
" Beyond that, though, the feature encourages using the
same variable name inside and outside the function definition, which has
some downsides: "the first is that it makes refactoring (a little)
harder, and the second is that it discourages using more meaningful, less
generic names for the variables in the caller
".
But Angelico noted
that the statistics tell a different story: "[...] this already
happens in huge numbers of places. Clearly it's often the best choice even
without this feature.
" Bambrick's changes for the standard library,
and a similar example PR for
pandas seemed to harden the opposition to the feature somewhat.
Several responses in the thread indicated that the changes did not improve
readability, at least for most commenters, though there were also a few new
messages in support.
Some other possibilities for the syntax were mooted, though no real consensus emerged. Like many others, it is a proposal with some strong advocates and roughly as many naysayers. The PEP should help further the discussion, but the feature may well be too niche—and too disruptive—to go much beyond that. As alluded to by Moore and others, there seems to be some concerted effort toward proposing fairly small changes at the corners of the language these days. It remains to be seen whether the steering council (or its delegate) is amenable to that.
| Index entries for this article | |
|---|---|
| Python | Arguments |
| Python | Enhancements |
