Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakelevi1996/2945fe4278b7c69af20512ad987ff141 to your computer and use it in GitHub Desktop.
Save jakelevi1996/2945fe4278b7c69af20512ad987ff141 to your computer and use it in GitHub Desktop.
Mutable types, immutable types, names, and objects

Mutable types, immutable types, names, and objects

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)

Functions

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 of foo to the object the argument bar is bound to when the function is called.

  • If bar refers to a mutable object and foo 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 that foo can do is create a name bar 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment