I think a main benefit of this feature would be to emphasize one parameter that’s slightly different among many trivial pass-through parameters.
Auto-formatters definitely should not convert code automatically though. That would defeat almost the entire benefit IMO. You would never know if a parameter is specifically emphasized due to explicit intent of the author or due to an auto-formatter gone awry.
I’ve seen many messages here, different syntax proposals in the PEP and in the other discuss thread.
It seems that no agreement can be reached because none of the syntax is explicit enough to understand the use-name-as-kwarg feature (both f(x=) and f(x=) seem weird because something is missing).
I was wondering if something like f(x=!) could be more explicit for this purpose. ! already has this look-what-is-defined-before behaviour in the shell for example.
Maybe it’s not the best solution but at least we see that there is something after the = and even if we don’t know this syntax we understand that it is based on this exclamation mark.
I suspect adopting such an “all or nothing” convention would lead to people declaring variables right before calling a function simply so they could use the condensed form, i.e.
bar = some_call()
do_thing(foo=, bar=, baz=)
versus
do_thing(foo=, bar=some_call(), baz=)
So I guess a natural question is, which of these two do people prefer? Especially people who have expressed a dislike of the latter.
In real world code, my position might be a little less black and white. Ultimately, readability and maintainability are more important than any absolute rule. But my baseline is “all or nothing, and you aren’t allowed to cheat by creating variables just to satisfy the rule”
I don’t have to make a choice, though, do I? I’ll simply not use either option, and reject them in any code I control. If someone added a dummy variable just to avoid the “mixture” situation, that would be pretty obvious and I’d reject it just as fast as I’d reject the “mixed” approach. If you’re asking about the specific example you gave, I don’t feel the need to take a view on an artificial example. And as for code I encounter and have to read, but can’t dictate policy on, there are hundreds of ways people can write code that I’d find ugly or unacceptable. This is just one more.
So sorry, my only answer is “neither, if you want a black and white answer, but maybe I might think differently in a given context”.
When I was young, I was so desperate to lack a feature like this that I would use func(**locals()) syntax. Pls don’t shame.
I used to do this (or dictionary unpacking) for Python 3 string formatting (pre-f-strings.) I liked named arguments, but the ridiculous verboseness of the string formatting made me hate it:
first_name = 'John'
last_name = 'Cleese'
favorite_animal = 'penguin'
# So much duplication
"{first_name} {last_name}'s favorite animal is the {favorite_animal}".format(first_name=first_name, last_name=last_name, favorite_animal=favorite_animal)
# PEP 736 proposed. Slightly better, still not as nice as f-strings
"{first_name} {last_name}'s favorite animal is the {favorite_animal}".format(first_name=, last_name=, favorite_animal=)
# Condensed with dictionary unpacking
"{first_name} {last_name}'s favorite animal is the {favorite_animal}".format(**globals()) # you would use the proper dictionary based on context, such as locals()
One of the beauties of this sort of feature is that we don’t actually have to debate about whether it’s better to be consistent or to let differences be visible. Both options are available and people can do whichever makes sense!
Hi. I read the PEP, and I agree with the base point of it and disagree with the objections listed (and answered) in it.
However, I would like to go back to a point which I didn’t see addressed in this thread or in the PEP, apologies if it was mentioned in the base thread (I didn’t read it all).
The point about IDE finding the uses of the local variables in the new syntax is correctly answered in my opinion : making it switch to the non-shorthand kwarg syntax when renaming the local variable, or at the very least abort the renaming and explain why, that’s not trivial to implement but at least it’s simple to figure out how the IDE should behave.
However, highlighting is a bit different. When I put the caret on a local variable in VSCode, it highlights the use of the local variable. When I highlight the keyword part of a keyword argument in a function call, it highlights the keyword in the function’s signature, as well as its use inside the called function. And I would hate it if the IDE didn’t make the difference with the same name being used as an attribute, or as an unrelated variable outside the function/class.
If I put the caret on the new syntax, how is the IDE supposed to behave ? Should it highlight only one of the local variable, only the keyword parameter ? Should it highlight both, hiding the differences between the two ?
I wouldn’t consider it a blocking issue but I think it deserves being thought about.
Given that IDEs already do this for languages like JavaScript that have punning, presumably they’ll do the same for Python (and I too would love to know what that is if someone is willing to do a survey!)
One subtle difference in this case is that in JavaScript the identifier is semantically the variable and the name is inferred, while in this proposal the identifier is the name and the variable is inferred. Which likely means semantic analysers will need to do more substantial surgery in order to allow a (hypothetical) ArgumentName item match with Identifier items, rather than simply matching two Identifier items as they already do.
Also worth pointing out that I’m not aware of any editors that use the same analyser for multiple languages (except perhaps JS+TypeScript), and practically none who have the same people developing multiple languages. The fact that one language can already do it is close to meaningless for a second language.
I’m strongly opposed to Python including this feature.
There’s some arguments here that “if you don’t like it, then just don’t use it”. That’s not really a valid argument. In any organization larger than a single person, this would need investing time in composing style guides and/or linters. If black starts blindly enforcing this, it would mean lots of work to avoid it. I also don’t control or maintain all pieces of code that I read.
There’s also two points that haven’t seen discussed yet.
The first is the fact that, while the new syntax is currently a syntax error, it is also syntax that is very commonly typed on the way to typing out a full keyword-argument line. At the exact point of having a line that looks like some_param=, it’s not uncommon for me to context switch to read documentation. It’s therefore also not uncommon for me to find my own partial work in this state and to run tests to figure out where I was. I’m worried that the new syntax will make it more cumbersome to figure out where such a partial statement is, and that ultimately it will result in a bug due to name conflicts (some global name conflicting with the parameter at the call site).
My other worry is that this will be detrimental to IDE functionality. Currently a keyword argument like foo=foo has two interactive targets in my IDE, where I click either the left-side foo or the right-side foo to go to variable definition and parameter definition respectively. They also both show individual tooltips with data about the two distinct components (the local name, and the parameter). Since I’m an avid user of black (and because black is very popular), and black maintainers promise to enforce this feature, it’s clear that this PEP will lead to me losing very useful IDE functionality.
And speaking of IDEs, this really seems like a feature that would be better implemented at the visual presentation layer of code.
Other than that, I strongly agree with most if not all points raised by @pf_moore.
Black is highly opinionated. If you don’t like black’s choices, you don’t use black. From my understanding, this is a feature - you are relieved of the mental burden of having an opinion on whether this shorthand is good or bad.
But why should a feature be judged by how black may or may not use it? Do people moan that Python permits tabs AND spaces as indentation, on account of linters and formatting tools complaining at you if you’re inconsistent? No; we welcome the flexibility.
Again, this is a tooling problem, not a language one. And in this case, it should be relatively easy for IDEs to solve this, because other languages (such as JavaScript) have a similar feature. How do IDEs cope with JavaScript’s object shorthand, where {foo: foo} can be written as {foo}? Do the same for Python argument shorthands.
But it has semantic difference, in that it represents programmer’s intent for this to be the same name as the argument. My personal view is that linters should not change whether it’s in shorthand or longhand form. This is not merely a ligature, like displaying != as ≠ or lambda as λ. It is a way of expressing the concept of “pass this as a keyword argument with the same name”.
However, if linter authors choose to see this otherwise, they are of course free to do so, and to enforce the use (or non-use) of this shorthand. That’s why we HAVE different linters.