ProgrammingBackend Developer

What is the difference between passing arguments by reference and by value in Python? How does Python implement this mechanism and why is it important to distinguish between them when designing functions?

Pass interviews with Hintsage AI assistant

Answer.

Understanding how Python passes arguments to functions is crucial to prevent unexpected data changes and to design code correctly.

History of the Issue

In traditional programming languages like C or Java, arguments are passed by value (copy by value) or by reference (copy by reference). However, Python uses a different model — call by object reference (sometimes called "call by sharing").

The Problem

Many developers mistakenly believe that Python always passes arguments by reference or by value. This inevitably leads to situations where mutable objects are unexpectedly modified in the calling code.

The Solution

In Python, the values of function parameters are references to the objects that are passed to the function. This means:

  • If the object is mutable (mutable: list, dict, set…) — it can be modified inside the function, and this will reflect outside.
  • If the object is immutable (immutable: int, str, tuple, frozenset), trying to change it inside the function will create a new object and will not affect the external one.

Example:

# list - mutable (mutable) def add_item(lst): lst.append(42) my_list = [1, 2, 3] add_item(my_list) print(my_list) # [1, 2, 3, 42] # int - immutable (immutable) def add_num(x): x = x + 1 num = 10 add_num(num) print(num) # 10

Key Features:

  • Mutable objects can be changed inside the function — these changes are visible outside.
  • Immutable objects are not affected by the function — only new objects are created.
  • Python never automatically copies arguments; even mutable structures are always passed "by reference".

Tricky Questions.

Are arguments always passed by reference in Python?

No, in Python, references to objects are passed, and how an object behaves depends on whether it is mutable or not. An immutable object will create a new object upon any modification.

Can a function reassign a mutable argument to affect the external object?

No. If you assign a new value to a parameter inside a function, the external object will not change — you are only changing the local reference.

Example:

def reassign_list(lst): lst = [99, 100] my_list = [1, 2, 3] reassign_list(my_list) print(my_list) # [1, 2, 3]

Why might a function that accepts a list by default behave strangely on subsequent calls?

Because the default value is created once — at the function definition, and if it is modified (for example, by adding an element), it will change for all subsequent calls.

def add_element(x, cache=[]): cache.append(x) return cache print(add_element(1)) # [1] print(add_element(2)) # [1, 2]

Common Mistakes and Anti-Patterns

  • Using mutable default arguments (as in the last example).
  • Expecting that a function will not modify a passed list or dict, even though it does modify it.
  • Confusing the effects of functions when working with mutable and immutable objects.

Real-Life Example

Negative Case

A programmer passes a list to a function and expects that the original list will not change, but the function adds an element.

Pros:

  • Fast operation, no data copying.

Cons:

  • Unexpected side effects, bugs in large code if someone is unaware of argument modifications.

Positive Case

A programmer explicitly copies the list inside the function if they need to return something but not change the original:

def process_data(data): data = data.copy() # or list(data) # safe operation with a copy data.append('report') return data

Pros:

  • No unwanted side effects, the original is protected.

Cons:

  • For large objects — memory/time costs for copying.