Common Pitfalls When Using Python Lists: Mutability, Function Arguments, Class Initialization, and Method Return Values
This article explains why Python lists are mutable objects, illustrates how passing them to functions or using them as default class arguments can cause unexpected side‑effects, and warns that methods like append and extend modify the list in‑place without returning a new value.
Python lists are the simplest and most frequently used container, acting like a basket that can hold items of any type, and they are mutable objects whose values can be changed without creating a new object.
1. Lists are mutable objects
The following code shows that two variables referencing the same list share the same identity, and modifying the list through one variable affects the other:
a = [1,2,3]
b = a
print(f'before: id(a) = {id(a)},id(b) = {id(b)}')
a.append(4)
print(f'after: a = {a}, b={b}')
print(f'after: id(a) = {id(a)},id(b) = {id(b)}')Because the list object’s value changes while its address stays the same, all variables that reference it see the updated content.
2. Pitfall 1 – Using a list as a function argument
When a list is passed to a function, the function receives a reference to the original object, so in‑place modifications inside the function affect the caller’s list:
list_outer = [1,2,3,4]
print('in the function outside, the list id is {}'.format(id(list_outer)))
def list_append_100(a):
print('in the function inside, the list id is {}'.format(id(a)))
a.append(100)
list_append_100(list_outer)
print('after call the function, list_outer is:', list_outer)If you need to avoid this side‑effect, make a deep copy of the list before modifying it.
3. Pitfall 2 – Mutable default arguments in class constructors
Using a mutable default argument (e.g., parameter=[] ) causes all instances to share the same list, leading to unexpected cross‑instance changes:
class machine():
def __init__(self, id, parameter=[]):
self.id = id
self.parameter = parameter
def add_parameter(self,p):
self.parameter.append(p)
def remove_parameter(self,p):
self.parameter.remove(p)
photo_A = machine("ASML_01", ['LENS_TEMP','AIR_TEMP'])
print(f'photo_A id is {photo_A.id}, photo_A parameter is {photo_A.parameter}')
photo_A.add_parameter('CO2_PRES')
print('after add, the photo_A parameter is {}'.format(photo_A.parameter))Creating two machines without providing a parameter list makes both objects share the same empty list, so modifying one affects the other. Supplying a fresh empty list for each instance solves the problem:
# Creating two devices with separate empty lists
Etch_B = machine('LAM-XR002', [])
Track_B = machine('TEL_BF02', [])
print(Etch_B.id, Etch_B.parameter, id(Etch_B.parameter))
print(Track_B.id, Track_B.parameter, id(Track_B.parameter))
Track_B.add_parameter('PR_weight')
print('after add, Track_B parameter is {}'.format(Track_B.parameter))
print('after add, Etch_B parameter is {}'.format(Etch_B.parameter))4. Pitfall 3 – List methods like append, extend, remove return None
Methods that modify a list in place do not return the modified list; they return None . Assigning the result to another variable will give None instead of a copy:
a = [1,2,3]
b = a.append(4) # b is NoneBe aware of this behavior to avoid unexpected None values.
Understanding these pitfalls helps you use Python lists safely and avoid subtle bugs.
DataFunSummit
Official account of the DataFun community, dedicated to sharing big data and AI industry summit news and speaker talks, with regular downloadable resource packs.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.