4 ms·
Default list/dict arguments is the one that comes to mind. Yes, I know why it happens, no, it’s still bad because it trips up every beginner.
by scott_w 4mo ago
Default list/dict arguments is the one that comes to mind. Yes, I know why it happens, no, it’s still bad because it trips up every beginner.
- tasuki 4mo agoWhy does it happen?
- NekkoDroid 4mo agoDefault arguments are only evaluated once and assigned the same instance to every call that doesn't specify that argument. So when you assign a new list as a default argument and then append to that list, the next call will already have one element in that list. So what you need to do is have it "None-able" and within the function create a new list.
- LtWorf 4mo agoYou can use anything immutable like a string, a number, a tuple of immutables, a frozendict, any dataclass with frozen=True, and so on. No need to do the annoying if x is None.
- tasuki 4mo agoYes I know as much, but why? Is it for speed? Python is slow anyway, so no big deal. Incompetence? Malice perhaps?
- LtWorf 4mo agoIt's just because the `def xxx()` part gets executed once when the module is loaded so the default arguments get created then. It's not really a design choice. If you declare a function inside a for loop with the default argument set to a list, it will be re-declared at every iteration of the loop and the list of the default argument will be a new instance every time.
- tasuki 4mo ago> It's just because the `def xxx()` part gets executed once when the module is loaded so the default arguments get created then. I understand as much. > It's not really a design choice. That explains it then. Pretty damning though, no?
- NekkoDroid 4mo agoI don't have any evidence for my theory, but I assume it is because arguments are processed mostly on the function side instead of the call site. My assumption just makes sense when all the function really gets is "a list of positional arguments and a dict of keyword arguments" (ala `*args, **kwargs`) that is "deconstructed" to the named variables on the function side. Then the function never gets the default value passed and fills it in before executing the body. Therefore it needs some value to assign and that value is determined when parsing the function definition. So effectively I want to say that I think instead of the default value being passed at the call site (which is how C++ for example does it by inserting the expression inplace of a specified value) it is filled in by the function before executing the body. In the end this is just a guess, but that is my working hypothesis.
- ptx 4mo agoFunction definitions in Python are just statements that are executed. When you execute the "def" statement, the default values are evaluated. You can try it in the REPL: >>> def f(foo=print("Executing def statement!")): ... print("Executing function body.") ... Executing def statement! >>> f() Executing function body. There's a fairly straight-forward explanation of this in the documentation: https://docs.python.org/3/reference/compound_stmts.html#function-definitions https://docs.python.org/3/reference/compound_stmts.html#func... "Default parameter values are evaluated from left to right when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call."