I was reading this very informative question and answer and learned about this behavior for the first time: calling
def foo(l=[]):
l.append(1)
print(l)
foo()
foo()
foo([])
foo()
prints
[1]
[1,1]
[1]
[1,1,1]
I thought that was neat and wanted to try it with other variable types as default arguments.
Running
import math
def foo(l=[],bar=0,baz={"z":0},bap="a"):
l.append(1)
bar+=1
baz["z"]+=1
bap=chr(ord(bap)+1)
print(locals())
foo()
foo()
foo([],math.pi,{"z":0},"?")
foo()
prints
{'l': [1], 'bar': 1, 'baz': {'z': 1}, 'bap': 'b'}
{'l': [1, 1], 'bar': 1, 'baz': {'z': 2}, 'bap': 'b'}
{'l': [1], 'bar': 4.141592653589793, 'baz': {'z': 1}, 'bap': '@'}
{'l': [1, 1, 1], 'bar': 1, 'baz': {'z': 3}, 'bap': 'b'}
which caught me totally off-guard. I was expecting incrementing the integer bar
and string bap
to be analogous to appending/modifying elements of l
and baz
and cause similar behavior, but it didn't - they print the same values each foo
call (unless non-default arguments are provided).
Hence the question in the title. I was thinking that the difference was caused by iterable versus non-iterable data types in my example.