Settings

Theme

The Perils of Default Arguments in Python

eaj.no

1 points by going_north 9 months ago · 1 comment

Reader

zahlman 9 months ago

Yes, this is the subject of one of the "classic" posts of OG Stack Overflow (https://stackoverflow.com/questions/1132941). And in fact it commonly gets deliberately abused (https://stackoverflow.com/questions/3431676) despite better tools being available for the intended effect (https://stackoverflow.com/questions/277922).

But it's good to have more writeups, I suppose. And it's good to point out that the initializers of a `dataclass` will show the same kind of early binding, and how to use `default_factory` instead. (It's not immediately obvious that this is related to the issue with function arguments, but it is.)

> That is a very roundabout way of saying that if you do this... the default argument value for base_url will be "eaj.no", and not "example.com".

This isn't a good example. Even in a hypothetical alternate Python where `base_url` had its default value read at call time, `some_function` isn't called anywhere, nor does it modify the global `default_url`, so there's no reason why the behaviour of `get_post_url` would change.

> Notably, we can also pass a variable as the default argument value.

No; as already established, a value is used - the value that results from evaluating the expression `default_url` (which happens to consist of just a variable name). Also, default argument values aren't "passed" - that's the point.

> In short, default arguments should never be used for values that are required to change between function calls.

More accurately, subsuming the previous section: they should not be used for values that must be determined at the time the function is called. Because that isn't what happens.

> Use None as a sentinel value and conditionally create the mutable default value in the function body instead.

This is the standard advice, but I hate it. "Special cases aren't special enough to break the rules"; `None` is overly magical in a lot of Python code. Besides, writing code that modifies the passed-in value and then also `return`s a value isn't Pythonic - https://en.wikipedia.org/wiki/Command%E2%80%93query_separati... is a key part of the design of the standard library and of several builtin methods. Maybe you expect the caller to use a temporary for every call, but maybe the caller didn't understand that.

A lot of the time, a better approach is to just use an equivalent immutable value.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection