
Gavin R. answered 10/23/20
Experienced Coding Instructor and Tutor
This is a great question.
One of the aspects of Python that makes it really fun to work with is that it is compiled at runtime. It allows a lot of freedom with how we write code, but can also lead to some confusing results. Have you tried giving 'foo' a list after running it a few times?
foo() //-> [5]
foo() //-> [5,5]
foo([1,2,3]) //-> [1,2,3,5]
foo() //-> [5,5,5]
This happens because the Python compiler creates a unique foo object when foo is called using the default arguments. When we call foo() the first time, a foo object is instantiated and the 'a' variable is created within its namespace [foo.a]. The next time foo() is called using the defaults, the compiler recognizes that this function already exists. The same foo object is used, therefore the same 'a' variable is used.
I agree that this behavior is unexpected, but I would not call it a 'dramatic design flaw'. It is one of the ways in which Python is more of an object oriented language. This attribute of functions allows us to use a function as an object without having to build a class or give it a name. That's pretty cool, if you ask me!