The following statements are quotes from Jeff Knupp's blog-post "Is Python call-by-value or call-by-reference? Neither."
In Python a variable is not an alias for a location in memory. Rather, it is simply a binding to a Python object.
- Changes to a mutable object are visible through all names bound to it. Python's lists are an example of mutable objects.
- The value of immutable objects can not be modified after they are created. They can be used to compute the values of new objects.
When you think about it, this dichotomy is necessary because, again, everything is an object in Python. If integers were not immutable I could change the meaning of the number '2' throughout my program.
Which is to say, a variable
is a name
which points to/is bound to an object
(Don't believe me? Check out Section 7.2 of the Python Language Reference).
The following types are immutable:
tuple
range
str
(IE strings)bytes
frozenset
int
float
Most other types in Python are mutable, including lists, classes, and class instances.
Lets look at some code involving mutable and immutable variable assignments:
# Lists are mutable sequences: they can be changed
mutable_sequence = [1, 2, 3, 4]
# Tuples are immutable sequences: they cannot be changed
immutable_sequence = (1, 2, 3, 4)
# Bind `x` to the object which is pointed to by `mutable_sequence`
x = mutable_sequence
# Modify the object that `x` points to
x += x
# `mutable_sequence` still points to the object that was just changed
print(mutable_sequence)
# >>> [1, 2, 3, 4, 1, 2, 3, 4]
# Bind `x` to the object which is pointed to by `immutable_sequence`
x = immutable_sequence
# The immutable object can't be changed,
# so a new object is created and `x` is bound to it
x += x
# The [immutable] object pointed to by `immutable_sequence` is unchanged
print(immutable_sequence)
# >>> (1, 2, 3, 4)
print(x)
# >>> (1, 2, 3, 4, 1, 2, 3, 4)
Here are some more quotes from Jeff Knupp's blog-post:
By now, you should almost be able to intuit how function calls work in Python. If I call
foo(bar)
, I'm merely creating a binding within the scope offoo
to the object the argumentbar
is bound to when the function is called.
- If
bar
refers to a mutable object andfoo
changes its value, then these changes will be visible outside of the scope of the function.- On the other hand, if
bar
refers to an immutable object, the most thatfoo
can do is create a namebar
in its local namespace and bind it to some other object.
Let's look at some more code:
def append_sausage_list(sequence):
sequence += list('sausage')
print(sequence)
def append_sausage_tuple(sequence):
sequence += tuple('sausage')
print(sequence)
mutable_list = [1, 2, 3, 4]
# The name `mutable_list` (which points to a mutable list-object)
# is used as a parameter to the function `append_sausage_list`;
# the mutable list-object (which `mutable_list` points to)
# is then modified from within the scope of the function.
append_sausage_list(mutable_list)
# >>> [1, 2, 3, 4, 's', 'a', 'u', 's', 'a', 'g', 'e']
# Changes to the list persist beyond the scope of the function:
print(mutable_list)
# >>> [1, 2, 3, 4, 's', 'a', 'u', 's', 'a', 'g', 'e']
immutable_tuple = (1, 2, 3, 4)
# The name `immutable_tuple` (which points to an immutable tuple-object)
# is used as a parameter to the function `append_sausage_tuple`;
# the immutable tuple-object (which `immutable_tuple` points to)
# cannot be modified from within the scope of the function (or anywhere else),
# so a new object is created which `sequence` points to
append_sausage_tuple(immutable_tuple)
# >>> (1, 2, 3, 4, 's', 'a', 'u', 's', 'a', 'g', 'e')
# The tuple pointed to by `immutable_tuple` is unchanged:
print(immutable_tuple)
# >>> (1, 2, 3, 4)
One final banger from Jeff:
In Python, (almost) everything is an object. What we commonly refer to as "variables" in Python are more properly called names. Likewise, "assignment" is really the binding of a name to an object. Each binding has a scope that defines its visibility, usually the block in which the name originates.