On Fri, Apr 17, 2020 at 11:57 AM Steven D'Aprano <st...@pearwood.info>
wrote:

> On Fri, Apr 17, 2020 at 11:25:15AM +0200, Alex Hall wrote:
>
> > I don't think you really need to know what it means to read the code for
> > most purposes.
>
> *blink*
>
> > You look at the function call and you can see a bunch of
> > names being passed to self.do_something. If the function call has
> > 'keyword=keyword' in it instead of just 'keyword', that's not adding much
> > information.
>
> Of course it adds important information! It is adding the critical
> information: which parameter gets assigned the specified value.
>

Of course it's adding some information, but it's not information a reader
usually has to think about.


> Put yourself in the position of someone who doesn't know the meaning of
> the * in a function call. What's the difference between these two calls?
>
>     f(x)
>     f(*, x)
>
> It's not good enough to merely say that you're passing an argument `x`.
> That's true of both calls. There must be a difference between the two,
> otherwise why have the star?
>

Readers don't generally have to compare two similar looking pieces of code.
If they do, it's generally in a conversation with someone
(e.g. when reviewing a PR) and they can ask that person what the asterisk
means.
So "What's the difference between these two calls?" is not usually a
relevant question.

Positional arguments tell us that values are assigned to parameters from
> left to right:
>
>     function(spam,  # first parameter
>              eggs,  # second parameter
>              cheese,  # third parameter
>              )
>
> but we have no clue at all what the names of those parameters are.
> That's the down-side of positional arguments, and one of the reasons why
> positional arguments don't scale. Knowing the names of the parameters is
> often important.
>
> Keyword arguments fill in the missing critical information:
>
>     function(alpha=spam,
>              beta=eggs,
>              gamma=cheese,
>              )
>
> and we can shuffle the order around and the mapping of argument value to
> parameter name is still clear.
>

That doesn't matter here because the parameter and variable names have to
match to use the shortcut.


>
> > The technical details of how an argument is being passed are
> > usually not important to readers.
>
> I don't care about the argument passing implementation. I care about the
> meaning of the code. Here is a real-world case:
>
>     open('example.txt', encoding, newline, errors, mode)
>
>     open('example.txt', *, encoding, newline, errors, mode)
>
> Would you agree that the two of those have *radically* different
> meanings? The first will, if you are lucky, fail immediately; the second
> may succeed. But to the poor unfortunate reader who doesn't know what
> the star does, the difference is puzzling.
>

> This holds even more strongly if the various parameters take the same
> type:
>
>     # a real signature from one of my functions
>     def function(
>            meta:bool,
>            dunder:bool,
>            private:bool,
>            ignorecase:bool,
>            invert:bool)
>
>     function(dunder, invert, private, meta, ignorecase)
>     function(*, dunder, invert, private, meta, ignorecase)
>


No reader will ever have to think about the difference. They will simply
see the second version and know which arguments are being passed.
Also, your examples are clearly demonstrating that using the shortcut makes
it easier to avoid mistakes.

I'm not really sure what you're actually concerned about. Can you give a
hypothetical scenario explaining how someone would be confused in practice?
Here's the worst case scenario I can imagine:

A reader is trying to debug some code that isn't behaving right. The call
`function(*, dunder, invert, private, meta, ignorecase)` isn't doing what
they expect. if they put a breakpoint or some prints inside `function` they
would probably see that the variables `dunder`, `invert`, etc. have the
correct/obvious values inside, but they don't. Instead they visually
inspect the function call and the function definition. They don't know what
'*' means, and they don't bother to find out, so they think arguments are
being passed positionally. They compare the positions of the arguments and
parameters in the call and definition and see they don't match, and they
think that's the problem. They try to fix the call by rearranging the
arguments or switching to explicit keyword arguments. That doesn't change
the behaviour of the program so they spend some time being confused about
that.
_______________________________________________
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/KUYBMVMYRTHCHE3PCO6TTGILYA4UC5AN/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to