Strict Function Parameters in Python

2022-01-23

I was shocked to come across a Hacker News post about enforcing strict function parameters in Python, because I had no idea such a feature existed.

The idea is that Python functions support arguments in various formats:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def func(x, y, z):
    return x + y + z

# Positional only
func(1, 2, 3)

# Positional and keywords
func(1, y=2, z=3)

# All keywords
func(x=1, y=2, z=3)

# All keywords with **kwargs
func(**{'x': 1, 'y': 2, 'z': 3})

But we can restrict the caller format by using the / and * symbols like so:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# Anything to the left of `/` must be passed only by position.
def positional_only(x, y, z, /):
    return x + y + z

positional_only(1, 2, 3)      # OK
positional_only(1, y=2, z=3)  # TypeError

# Anything to the right of `*` must be passed only by name.
def kwarg_only(*, x, y, z):
    return x + y + z

kwarg_only(x=1, y=2, z=3)  # OK
kwarg_only(1, 2, 3)        # TypeError

# `/` and `*` can be combined.
def positional_and_kwarg(x, y, /, *, z):
    return x + y + z

positional_and_kwarg(1, 2, z=3)  # OK
positional_and_kwarg(1, 2, 3)    # TypeError

I can see this being situationally useful. For example, we can use this to prevent calling code from coupling to the specific names of positional arguments (which would prevent us from easily renaming them in the future).

But otherwise, I'm still not sure how I feel about this change, which adds more complexity to Python for minimal gain.

For further reading

  • PEP 570, which introduces /
  • Pydantic (via nyellin on HN) which creates data validation and parsing libraries via type hints