Syntactic sugar to encourage use of named arguments

@joshuabambrick What’s status here?

Thanks both. The PEP has been drafted and I will create a pull request on the main peps repo tomorrow.

3 Likes

What’s the proposed error messages?

In this program:

def f0():
    pass

def f1(whatever):
    pass

def f2(whatever=None):
    pass

def f3(whatever, whenever):
    pass

print("Runtime")
f0(whatever=)
f1(whatever=)
f2(whatever=)
f2(whatever=doesnt_exist)
f3(whatever=
   "a second argument")

whatever="Hello"
f0(whatever=)
f1(whatever=)
f2(whatever=)
f2(whatever=doesnt_exist)
f3(whatever=
   "a second argument")


You currently get told:

    f0(whatever=)
                ^
SyntaxError: invalid syntax

Which makes sense, as it is invalid syntax. It’s easy for a beginner to look at and google, it’s instructive for an expert. It’s also picked up by the interpreter when it reads the file, rather than when it’s executed, and so it’s instant. If you uncomment the calls to f0-f2 then you get a runtime NameError on doesnt_exist. And I’m sure we’ve all dealt with students and junior programs who don’t test their code enough and get a NameError after a few minutes of runtime.

What is the proposed errors under the new scheme? Is it all runtime error detection? How will it differentiate between the actual SyntaxError and the NameError?

(Personally I don’t like the post-fix, dangling equals, as it’s too much like the typos I make. I’ll take any other version over that! Even something ugly like whatever=&)

1 Like

Why not just this?:

TypeError: f0() got an unexpected keyword argument 'whatever'

All the previously existing errors should work just fine.

There’s a simple principle to answer this: f(whatever=) should work exactly like how f(whatever=whatever) works now. I think that should answer almost all questions about how the feature should work.

4 Likes

Exactly, thanks Jelle

1 Like

Notably, this is a call-site syntactic feature, and it won’t behave in any way differently depending on the function that’s being called.

One of the things that has always bugged me about class init, is the amount of boilerplate. I’d like to suggest we add a built-in called “setvalues” that takes an object and **kwargs, looping over the keyword arguments and setting them on the object. By adding this call with the proposed feature, a lot of boilerplate could be reduced.

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

becomes

class Car:
    def __init__(self, make, model, year):
        setvalues(self, make=, model=, year=)

If you don’t want to introduce another keyword, how about:

class Car:
    def __init__(self, make, model, year):
        self.(make=, model=, year=)

This came up before and got split off to a separate thread, because it’s really a separate idea: Assign corresponding parameter value when omitting RHS in __init__

1 Like

It’d be a pretty simple function, you could define it yourself:

def setvalues(obj, /, **kw):
    for attr, val in kw.items():
        setattr(obj, attr, val)
1 Like

Without a doubt. But then you’d have to have it somewhere and import it every single time you built this kind of boilerplate into your classes.

The request wasn’t so much about it being complicated, the request was more that it used the new feature to solve another problem without a change to the language, only an addition to the standard library.

I don’t think adding another mystery function (super is the other) will help much. IMO, if you want reduced boilerplate you use dataclasses, or one of the many great similar 3rd party libraries. This is a solved problem.

3 Likes

Adding a built-in function is a significant change to the language.

1 Like

Obviously I’m late to the party here, but I strongly dislike this change.

Personally I don’t think it improves readability at all. It saves some typing, but I’ve never really thought that was a good reason for syntax changes by itself. I thought this was a misfeature when it was added to JavaScript, and encountering it in the wild has only served to convince me that I was right.

I have opinions on which syntax I hate least, but I’ll leave those out, because I think the whole idea is a net loss.

But aside from my personal distaste for this, as someone who helps run a user group and therefore answers questions from beginners (both to programming and to Python) on a regular basis, I guarantee that this will be one of those questions that comes up as a point of confusion over and over again.

Consider:

  • Explaining why sometimes you have to put a value and sometimes you don’t
  • Explaining why someone’s code just exploded because their implicitly-referenced variable isn’t defined where they thought it was
  • Explaining why someone’s code is returning the wrong results because they implicitly referenced a variable name but it didn’t have the value they actually wanted to pass into the function in it.

None of these are difficult to understand for someone who knows Python well, and are probably a very tiny lift for someone who is experienced using some other programming language. But these re the kinds of things that are large hurdles for those just starting out. The tiny amount of convenience gained is not worth the cost.

20 Likes

@joshuabambrick Can Chris’ comment, as well as the poll result be pinned to the top? Syntactic sugar to encourage use of named arguments - #131 by effigies

Personally, I would have a strong preference for f(*,x), since it mirrors the existing syntax for defining keyword-only parameters.

1 Like

Shouldn’t be necessary; the point of a PEP is to gather all that sort of information. We should soon be able to discuss this proposal using a living document that contains all the relative proposals, pros and cons, impact on existing code, etc.

Really not in favour of this proposal. The syntax looks confusing, maybe a different operator would be better than =. But:

Not sure I would want to tie my local variable name to some parameter name of a function I will call, because it is more simple (point 3 of the original post).

Point 2 - Is verbosity a problem? - I prefer explicit to implicit

Point 4 - really not the same

I can see a lot of learners getting confused when they accidentally get this wrong.

Experience from JavaScript’s object shorthand suggests that this isn’t as confusing as people say. It tends to be fairly common and not a problem to people’s comprehension.

1 Like

Mmm… Maybe if they decided to learn JavaScript before. But from my experience people come to python as their first language with no previous coding experience.

To them, x= is an assignment, and there should something on the rhs of the operator. Otherwise it’s a kind of magic, it wouldn’t be obvious to a learner that this syntax at this point was valid. That’s why I suggested a different character. I’m not against the proposal in principle if the resulting implementation is simple and clear to understand.