[Python-ideas] Keyword only argument on function call
Steven D'Aprano
steve at pearwood.info
Sat Sep 8 05:04:06 EDT 2018
On Fri, Sep 07, 2018 at 06:59:45AM -0700, Anders Hovmöller wrote:
> Personally I think readability suffers greatly already at two arguments if
> none of the parameters are named.
*At* two arguments? As in this example?
map(len, sequence)
I'll admit that I struggle to remember the calling order of list.insert,
I never know which of these I ought to write:
mylist.insert(0, 1)
mylist.insert(1, 0)
but *in general* I don't think two positional arguments is confusing.
> Sometimes you can sort of fix the
> readability with function names like do_something_with_a_foo_and_bar(foo,
> bar), but that is usually more ugly than just using keyword arguments.
It is difficult to judge the merit of that made-up example. Real
examples are much more convincing and informative.
> Functions in real code have > 2 arguments.
Functions in real code also have <= 2 arguments.
> Often when reading the code the
> only way to know what those arguments are is by reading the names of the
> parameters on the way in, because it's positional arguments.
I don't understand that sentence. If taken literally, the way to tell
what the arguments are is to look at the arguments.
I think you might mean the only way to tell the mapping from arguments
supplied by the caller to the parameters expected by the called function
is to look at the called function's signature.
If so, then yes, I agree. But why is this relevent? You don't have to
convince us that for large, complex signatures (a hint that you may
have excessively complex, highly coupled code!) keyword arguments are
preferable to opaque positional arguments. That debate was won long ago.
If a complex calling signature is unavoidable, keyword args are nicer.
> But those aren't checked.
I don't understand this either. Excess positional arguments aren't
silently dropped, and missing ones are an error.
> To me it's similar to bracing for indent: you're telling
> the human one thing and the machine something else and no one is checking
> that those two are in sync.
No, you're telling the reader and the machine the same thing.
func(a, b, c)
tells both that the first parameter is given the argument a, the second
is given argument b, and the third is given argument c.
What's not checked is the *intention* of the writer, because it can't
be. Neither the machine nor the reader has any insight into what I meant
when I wrote the code (not even if I am the reader, six weeks after I
wrote the code).
Keywords help a bit with that... it's harder to screw up
open(filename, 'r', buffering=-1, encoding='utf-8', errors='strict')
than:
open(filename, 'r', -1, 'utf-8', 'strict')
but not impossible. But again, this proposal isn't for keyword
arguments. You don't need to convince us that keyword arguments are
good.
> I have seen beginners try:
>
> def foo(b, a):
> pass
>
> a = 1
> b = 2
> foo(a, b)
>
> and then be confused because a and b are flipped.
How would they know?
Beginners are confused by many things. Coming from a background in
Pascal, which has no keyword arguments, it took me a while to get to
grips with keyword arguments:
def spam(a, b):
print("a is", a)
print("b is", b)
a = 1
b = 2
spam(a=b, b=a)
print(a, b)
The effect of this, and the difference between the global a, b and local
a, b, is not intuitively obvious.
--
Steve
More information about the Python-ideas
mailing list