| There's always tension between language simplicity (and thus cognitive load of the programmers) and features. Compare Scheme with Common Lisp. The idea in Python is: 1. Statements are executed line by line in order (statement by statement). 2. One of the statements is "def", which executes a definition. 3. Whatever arguments you have are strictly evaluated.
For example f(g(h([]))), it evaluates [] (yielding a new empty list), then evaluates h([]) (always, no matter whether g uses it), then evaluates g(...), then evaluates f(...). So if you have def foo(x = []):
... that immediately defines foo = (lambda x = []: ...) For that, it has to immediately evaluate [] (like it always does anywhere!). So how is this not exactly what it should do? Some people complain about the following: class A:
x = 3
y = x + 2
That now, x is a class variable (NOT an instance variable). And so is y. And the latter's value is 5. It doesn't try to second-guess whether you maybe mean any later value of x. No. The value of y is 5.For example: a = A()
assert a.__class__.x == 3
assert a.x == 3
a.__class__.x = 10
b = A()
assert b.x == 10
succeeds.But it just evaluates each line in the class definition statement by statement when defining the class. Simple! Complicating the Python evaluation model (that's in effect what you are implying) is not worth doing. And in any case, changing the evaluation model of the world's most used programming language (and in production in all countries of the world) in 2025 or any later date is a no go right there. If you want a complicated (more featureful) evaluation model, just use C++ or Ruby. Sometimes they are the right choice. |
> For that, it has to immediately evaluate [] (like it always does anywhere!). So how is this not exactly what it should do?
It has a lambda there. In many programming languages, and the way human beings read this, say that "when there is a lambda, whatever is inside is evaluated only when you call it". Python evaluating default arguments at definition time is a clear footgun that leads to many bugs.
Now, there is no way of fixing it now, without probably causing other bugs and years of backwards compatibility problems. But it is good that people are aware that it is an error in design, so new programming languages don't fall into the same error.
For an equivalent error that did get fixed, many Lisps used to have dynamic scoping for variables instead of lexical scoping. It was people critizing that decision that lead to pretty much all modern programming languages to use lexical scoping, including python.