Mutable Object
def foo(a=[]):
a.append(5)
return a
foo()
[5]
foo()
[5, 5]
foo()
[5, 5, 5]
Reason:
What causes the confusion is the behaviour you get when you use a “mutable” object as a default value; that is, a value that can be modified in place, like a list or a dictionary.
The function keeps using the same object, in each call.
It is a common mistake in Python to set a mutable object as the default value of an argument in a function
more:
https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument
https://stackoverflow.com/questions/9158294/good-uses-for-mutable-function-argument-default-values
http://effbot.org/zone/default-values.htm
foo([14])
[14, 5]
foo([14])
[14, 5]
# Though it looks like a fundamental flaw, you can use it for caching purpose like we do in lrucache
def add(name, cache={}):
if name in cache: return cache[name]
print('getting from expensive calculation')
cache[name] = result = (name[::-1])
return result
add('one')
getting from expensive calculation
'eno'
add('one') # This time it is coming from cache
'eno'
add('two')
getting from expensive calculation
'owt'
We will use it to calculate name meter
def get_name_meter(name, cache={}):
if name in cache:
return cache[name]
print('getting from expensive calculation')
chars = list(name) # name.split won't return chars
meter = 0
for c in chars:
meter += ord(c)
cache[name] = result = meter
return result
get_name_meter('Toronto')
getting from expensive calculation
757
get_name_meter('Toronto') # getting from cache
757
get_name_meter('Montreal')
getting from expensive calculation
834
Like above, we can use the mutable objects to take advantage of the situation