Keyword argument demystify

time to read 3 min | 637 words

There’s a lot of baffling among Python programmers on what exactly “keyword arguments” are. Let’s go through some of them.

If you somehow are writing for a Python 3 only codebase, I highly recommend making all your keyword arguments keyword only, especially keyword arguments that represent “options”.

There are many problems with this sentence. The first is that this is mixing up “arguments” (i.e. things at the call site) and “parameters” (i.e. things you declare when defining a function). So:

def foo(a, b):  # <- a and b are "parameters" or "formal arguments"
    pass

foo(1, 2)  # <- 1 and 2 are arguments to foo, that match a and b

This confusion is common among programmers. I also use the word “argument” when I mean “parameter”, because normally in conversation we can tell the difference in context. Even the documentation in the Python standard library uses these as synonyms.

The code above is the basic case with positional arguments. But we were talking about keyword arguments so let’s talk about those too:

def bar(a,    # <- this parameter is a normal python parameter
        b=1,  # <- this is a parameter with a default value
        *,    # <- all parameters after this are keyword only
        c=2,  # <- keyword only argument with default value
        d):   # <- keyword only argument without default value
    pass

So far so good. Now, let’s think about the statement we started with:

I highly recommend making all your keyword arguments keyword only

That implies there are keyword arguments that are not keyword only arguments. That’s sort of correct, but also very wrong. Let’s have some examples of usages of bar :

bar(1)         # one positional argument
bar(1, 2)      # two positional arguments
bar(a=1)       # one keyword argument
bar(a=1, b=2)  # two keyword arguments
bar(1, d=2)    # one positional and one keyword argument

The trick here is to realize that a “keyword argument” is a concept of the call site, not the declaration. But a “keyword only argument” is a concept of the declaration, not the call site. Super confusing!

There are also parameters that are positional only. The function sum in the standard library is like this: according to the documentation it looks like this:sum(iterable[, start]) But there’s a catch!

>>> sum(iterable=[1, 2])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: sum() takes no keyword arguments

And the start parameter can’t be used as a keyword argument either, even though it’s optional! Recap

(I’m using “argument” here even though “parameter” or “formal argument” would be more correct, but the Python standard library uses these all as synonyms so I will too, so my wording matches the documentation.)

Python functions can have :

  • Arguments that can be used both as positional and keyword arguments (this is the most common case)
  • Arguments that can be used both as positional and keyword arguments with default values (or just “arguments with default values”)
  • Positional only arguments (like the first argument tosum, this is uncommon and can only be achieved by functions implemented in C)
  • Positional only arguments with default values (like above, only for C)
  • Optional positional only arguments (2nd argument to sum, like above, only for C)
  • Keyword only arguments
  • Keyword only arguments with default values
  • Arbitrary positional arguments ( *args )
  • Arbitrary keyword arguments ( **kwargs )

When calling Python functions you can have:

  • Positional arguments
  • Keyword arguments

It’s very simple at the call site, but a lot more complex at the function definition, and how call site arguments are mapped to the declaration is quite complex.

Summary

Python appears simple because most of these rules and distinctions are so well thought out that many programmers can go years in a professional career and believe defaults arguments and keyword arguments are the same, and never get bitten by this incorrect belief.


Related Post:

  1. May 25, 2017 New interesting data structures in Python 3
  2. May 04, 2017 Looping techniques in Python
  3. May 03, 2017 Enhance your tuples
  4. May 02, 2017 Get more with collections!
  5. May 01, 2017 There is more to copying
  6. Apr 30, 2017 Implementing weak references in Python
  7. Apr 26, 2017 Next, Function or Method ?
  8. Apr 24, 2017 Generator Expressions
  9. Apr 23, 2017 Yield Keyword
  10. Apr 21, 2017 What are Generators?
  11. Apr 16, 2017 Lambda Functions in Python
  12. Apr 06, 2017 Function in Python are First-Class Object
  13. Apr 05, 2017 Django 1.11 Release Note a Reading
  14. Apr 03, 2017 One Hell Named JSON
  15. Dec 26, 2016 Queue in Python - Part 3
  16. Nov 02, 2016 Queue in Python - Part 2
  17. Nov 02, 2016 Queue in Python - Part 1
  18. Jun 25, 2016 Enable Spark Context on Your Ipython Notebook
  19. Apr 27, 2015 EAFP Coding Style in Python
  20. Jul 24, 2014 Kompresi CSS menggunakan Python