Concepts / Function Parameters and Mutable Objects

Function Parameters and Mutable Objects

The assignment b = a creates an alias, not an independent copy. After that assignment, a and b refer to the same object.

  • Programming
Interactive lab

Try it: Names and Objects

How Python variables are names bound to objects: assignment never copies, mutating a list is seen through every name that points at it, and ints are replaced rather than changed.

How it works

  1. name = object binds a name; b = a makes b point at the same object.
  2. Mutating a list (append, +=) changes the one shared object.
  3. a = a + [x] and y = y + 1 create NEW objects and re-point one name.
  4. Passing a list to a function passes the reference, so the function can change it.

Default run (7 steps): Two names, one list. Every name is a label that points at an object. … Printed: [1, 2, 3] / True

Simplified: Six fixed scripts on a tiny heap; you choose the values. Object numbers are illustrative, not real id() values.

Educational simulation

Loading the simulation…

One List, Two Names

Suppose a program uses two variables, a and b, for what appears to be the same list. If changing the list through b also changes what you see through a, the program may not contain two lists at all. It may contain one list with two variable names referring to it. This relationship is called aliasing.

Key point

The assignment b = a creates an alias, not an independent copy. After that assignment, a and b refer to the same object.

avariable[1, 2, 3]one list objecta is bTruebvariablerefers torefers tosame object
What does the relationship look like when a and b both refer to the same list, and how can is show that they are the same object?

Checking Identity

Python provides the is operator for testing object identity. The expression a is b is True when both variables refer to the same object and False when they refer to different objects. This is different from ==. The == operator tests whether two objects have equal values. Two variables can therefore contain equal-looking lists while still referring to different list objects.

python
Output
True
True

Both tests are True in this example, but they answer different questions. The equality test says that the values match. The identity test says that a and b refer to the same list object. The identity result is the important clue when investigating aliasing.

Mutation Through an Alias

What do you think happens?

After b = a and b.append(4), what will a contain?

  • Only [1, 2, 3]

  • [1, 2, 3, 4]

  • a will no longer refer to a list

Reveal answer
Answer:

[1, 2, 3, 4]

The assignment b = a gives both names access to one list. Because the list is mutable, modifying it through b changes the one shared object, which is also visible through a.

Code walkthrough
a = [1, 2, 3]
b = a
b.append(4)

print(a)
print(b)
  1. 1
    The first line creates one list and makes a refer to it.
  2. 2
    The second line creates an alias: b refers to that same list rather than receiving a new list.
  3. 3
    The third line modifies the shared list through b.
  4. 4
    The two print calls show the same modification because a and b refer to the same object.
  • a refers to a list containing 1, 2, and 3.
  • b is assigned the same object referred to by a.
  • The list is modified through b.
  • Both names now show the modified list.
Output
[1, 2, 3, 4]
[1, 2, 3, 4]
a[1, 2, 3][1, 2, 3]one shared lista[1, 2, 3, 4][1, 2, 3, 4]same shared listb[1, 2, 3]b[1, 2, 3, 4]refers torefers torefers torefers to
What changes after the shared list is modified through b, and why does the change appear through a as well?

Parameters and Shared Lists

A function parameter can refer to the same mutable list that the caller supplies. If the function modifies that list through its parameter, the caller can observe the modification through its original variable. The parameter is another name referring to the object passed into the function; it does not automatically make an independent list copy.

python
Output
["old", "new"]
values["old"]itemssame listappend("new")modifies listvalues["old", "new"]passed to functionused byvisible through
How does the caller's list become available through a function parameter, and why can a mutation inside the function affect the caller?
Key point

When debugging a function that unexpectedly changes a caller's list, inspect whether the function parameter and the caller's variable refer to the same object. The is operator helps verify that relationship.

Aliases and Independent Copies

If a program needs two lists whose later modifications are independent, create a copy explicitly. The source identifies a[:] and list(a) as ways to create an independent copy of a list. In contrast, b = a preserves the shared relationship.

OperationRelationshipEffect of modifying b
b = ab and a refer to the same listThe modification is visible through a
b = a[:]b refers to an independent list copyThe modification does not affect a
b = list(a)b refers to an independent list copyThe modification does not affect a

The assignment form determines whether two list variables share one object or refer to separate list objects.

python
Output
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 5]
b = asame objecta[1, 2, 3]a[1, 2, 3][1, 2, 3, 4]both names show changeb[1, 2, 3]b = a[:]independent copyb[1, 2, 3][1, 2, 3, 5]copy changes separatelyrefers torefers toshared mutationshared mutationoriginal listnew listseparate mutation
How do b = a and an explicit list copy differ in their object relationships and later behavior?

Tracing an Unexpected Change

Aliasing bugs often appear as an unexpected list change: one part of a program modifies a list, and another variable appears to change without being assigned. Trace the variables that refer to the list, then test likely pairs with is. If the test is True, a modification through either name affects the same mutable object.

original["ready"]original is workingTrueoriginal["ready", "changed"]original is workingTrueworking["ready"]working["ready", "changed"]identity checkidentity checksame objectsame object
How can comparing references before and after a mutation reveal why another variable changed unexpectedly?
  • Common mistake

    Assuming b = a creates a second list.

    What it looks like
    a = [1, 2]
    b = a
    Why it fails

    The assignment makes b refer to the same list object as a.

    Do this instead

    Use b = a[:] or b = list(a) when an independent list is required.

  • Common mistake

    Using == when the debugging question is whether two variables share one object.

    What it looks like
    a == b
    Why it fails

    Equality compares values, not object identity.

    Do this instead

    Use a is b to test whether the variables refer to the same object.

  • Common mistake

    Forgetting that a function parameter can refer to the caller's mutable list.

    What it looks like

    A function modifies its list parameter, and the caller's list changes.

    Why it fails

    The parameter can refer to the same list supplied by the caller.

    Do this instead

    Check the identity relationship and create a list copy when the function should work independently.

Best practice

When a list must not be changed through another variable or function parameter, make the independence explicit with a[:] or list(a). When a change is unexpected, test whether the two variables are aliases before searching for a more complicated cause.

Practice the Trace

MEDIUM

A program contains a list named scores. Another variable receives scores with the assignment backup = scores. Before any modification, decide what scores is backup will return. Then decide what scores will contain after backup is modified. Finally, describe one change that would make backup independent from scores.

Hints
  • Ask whether the assignment creates an alias or a copy.
  • Use the difference between is and == to identify the relevant test.
  • An independent list can be created with a slice or the list constructor.
Worked example

Tracing the Shared Object

Let scores = [10, 20], backup = scores, and then modify backup by adding 30. What identity relationship exists, and what values are visible through both variables?

  1. 1
    Identify the assignment

    The assignment backup = scores creates an alias rather than an independent copy.

  2. 2
    Test identity

    scores is backup is True because both variables refer to the same list object.

  3. 3
    Apply the mutation

    Adding 30 through backup modifies the shared list.

  4. 4
    Inspect both names

    Both scores and backup show [10, 20, 30] because each name refers to the modified object.

Result

The variables are aliases. To prevent the shared change, create backup with scores[:] or list(scores).

Key Takeaways

  1. 1
    Aliasing means that multiple variables refer to the same object.
  2. 2
    The assignment b = a creates an alias, not a copy.
  3. 3
    Use is to test identity and == to test equality of values.
  4. 4
    A mutation to a shared list is visible through every variable that refers to that list, including a function parameter.
  5. 5
    Use a[:] or list(a) to create an independent list copy when later modifications must remain separate.

At a glance

  • Aliasing occurs when two or more variables refer to one mutable object.
  • The is operator reveals whether two variables refer to the same object.
  • Mutating a shared list through one variable changes what other aliases observe.
  • Function parameters can refer to the caller's list and mutate that shared object.
  • Use a[:] or list(a) to create an independent list instead of an alias.

More concepts starting with F