Skip to content

Instantly share code, notes, and snippets.

@josemarcosrf
Created February 25, 2020 15:26
Show Gist options
  • Save josemarcosrf/5011ac543b450fa6c7e27dba23d35042 to your computer and use it in GitHub Desktop.
Save josemarcosrf/5011ac543b450fa6c7e27dba23d35042 to your computer and use it in GitHub Desktop.
Careful with python default list parameters!
class A:
"""This is an example of wrong functions default parameters:
This should actually be:
def __init__(self, l=None):
if l is None:
self.l = []
"""
def __init__(self, l=[]):
self.l = l
print(f"A.l mem: {id(self.l)}")
def f(a=1, b=[], do_return=False):
print(f"received a-mem: {id(a)}")
print(f"received b-mem: {id(b)}")
if do_return:
return b
# In this example, the list instance passed onto parameter 'b' is the same across
# function calls.
# The mem address of 'b' inside the function in both calls is the same!!
# Happens when we do not return 'b', so when the scope is limited to the function?
# See: http://effbot.org/zone/default-values.htm
b = f(a=5, b=[])
print(f"1st call (no return) -> returned b-mem: {id(b)}")
print("-" * 20)
b = f(a=4, b=[])
print(f"2nd call (no return) -> returned b-mem: {id(b)}")
print("*" * 40)
# But...
# When we do want 'b' returned, the mem address of 'b' inside the function
# is different during different calls:
b = f(a=5, b=[], do_return=True)
print(f"1st call (with return) -> returned b-mem: {id(b)}")
print("-" * 20)
b = f(a=4, b=[], do_return=True)
print(f"2nd call (with return) -> returned b-mem: {id(b)}")
print("*" * 40)
# This issue is much more dngerous when we have a class with instantiates
# an attribute from a false 'default list parameter':
a1 = A()
a1.l.append(1)
a2 = A()
a2.l.append(2)
# a1.l and a2.l are the same list! Hence we now have only one list with values=[1, 2]
print(a1.l)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment