Comment by mattclarkdotnet
5 days ago
Oh, and while we're at it, fix the "empty array is instantiated at parse time so all your functions with a default empty array argument share the same object" bullshit.
5 days ago
Oh, and while we're at it, fix the "empty array is instantiated at parse time so all your functions with a default empty array argument share the same object" bullshit.
We don't call them "arrays".
It has nothing to do with whether the list is empty. It has nothing to do with lists at all. It's the behaviour of default arguments.
It happens at the time that the function object is created, which is during runtime.
You only notice because lists are mutable. You should already prefer not to mutate parameters, and it especially doesn't make sense to mutate a parameter that has a default value because the point of mutating parameters is that the change can be seen by the caller, but a caller that uses a default value can't see the default value.
The behaviour can be used intentionally. (I would argue that it's overused intentionally; people use it to "bind" loop variables to lambdas when they should be using `functools.partial`.)
If you're getting got by this, you're fundamentally expecting Python to work in a way that Pythonistas consider not to make sense.
It's best practice to avoid mutable defaults even if you're not planning to mutate the argument.
It's just slightly annoying having to work around this by defaulting to None.
You don't need to use `None`. If you indeed aren't planning to mutate the argument, then use something immutable that provides the necessary interface. Typically, this will be `()`, and then your logic doesn't require the special case. I genuinely don't understand, after 20+ years of this, why everyone else has decided that the `None` check should be idiomatic. It's just, ugh. I'm pretty sure I've even seen people do this where a string is expected and `''` is right there staring at them as the obvious option.
Execution time, not parse time. It's a side effect of function declarations being statements that are executed, not the list/dict itself. It would happen with any object.
It's still ridiculous. A hypothetical Python4 would treat function declarations as declarations not executable statements, with no impact on real world code except to remove all the boilerplate checks.
There is no such thing as a "function declaration" in Python. The keyword is "def", which is the first three letters of the word "define" (and not a prefix of "declare"), for a reason.
The entire point of it being an executable statement is to let you change things on the fly. This is key to how the REPL works. If I have `def foo(): ...` twice, the second one overwrites the first. There's no need to do any checks ahead of time, and it works the same way in the REPL as in a source file, without any special logic, for the exact same reason that `foo = 1` works when done twice. It's actually very elegant.
People who don't like these decisions have plenty of other options for languages they can use. Only Python is Python. Python should not become not-Python in order to satisfy people who don't like Python and don't understand what Python is trying to be.
You think so but then you write a function with a default argument pointing to some variable that is a list and now suddenly the semantics of that are... what?
5 replies →
You are describing a completely different language, that differs in very major ways from Python. You can of course create that, but please don't call it Python 4 !
Let's not get started on the cached shared object refs for small integers....
What realistic use case do you have for caring about whether two integers of the same value are distinct objects? Modern versions of Python warn about doing unpredicatble things with `is` exactly because you are not supposed to do those things. Valid use cases for `is` at all are rare.
4 replies →
If you change this you break a common optimization:
https://github.com/python/cpython/blob/3.14/Lib/json/encoder...
Default value is evaluated once, and accessing parameter is much cheaper than global
there is PEP 671 for that, which introduces extra syntax for the behavior you want. people rely on the current behavior so you can't really change it