How Python passes arguments to functions
Understand shared objects, local rebinding, mutable defaults, and shallow copies when passing values to Python functions.
Python passes arguments by assignment: a function parameter becomes a local name for the object supplied by its caller. Mutating that shared object can be visible to the caller. Rebinding the local name does not rebind the caller's variable.
Rebinding leaves the caller's name alone
def double(value):
value = value * 2
print(value) # 10
number = 5
double(number)
print(number) # 5
The multiplication produces an integer result and assigns it to the local name value. The caller's number still refers to 5. Rebinding behaves this way even when the original argument is mutable: assigning items = [] inside a function does not replace the caller's list.
Mutating a shared object is visible
def add_item(items):
items.append(4)
numbers = [1, 2, 3]
add_item(numbers)
print(numbers) # [1, 2, 3, 4]
The function and caller refer to the same list. Item assignment, deletion, and mutating methods can all change it; mutation is not limited to append.
If you want a new value, return it and let the caller assign it:
def doubled(value):
return value * 2
number = doubled(number)
Avoid shared mutable defaults
A default expression is evaluated when the function is defined. A default list would therefore be reused across calls that omit the argument. Use a sentinel such as None when each call needs a new list:
def collect(item, target=None):
if target is None:
target = []
target.append(item)
return target
print(collect(1)) # [1]
print(collect(2)) # [2]
When the caller explicitly passes a list, this function still modifies that list.
Copy when the function should preserve its input
def added_copy(items):
result = items.copy()
result.append(4)
return result
original = [1, 2, 3]
result = added_copy(original)
print(original) # [1, 2, 3]
print(result) # [1, 2, 3, 4]
This is a shallow copy. Nested lists or other mutable members remain shared. Use a deliberate deeper-copy strategy when those members also need isolation.
FAQ
Which common objects are mutable? Lists, dictionaries, sets, and bytearrays are mutable. Integers, floats, strings, tuples, and frozensets are immutable. Hashability is not a reliable mutability test: a custom mutable object can be hashable, and an immutable tuple containing a list is unhashable.
Can a list inside a tuple change? Yes. The tuple keeps the same references in the same positions, but a referenced list can still be mutated.
References
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan