Scope and Side Effects
Unit ID: M05-U03 Estimated active time: 25-35 minutes
Function names are usually local
def calculate_total(base_hours, extra_hours):
total_hours = base_hours + extra_hours
return total_hours
The parameters and total_hours are local to the function call. Trying to use total_hours outside the function raises NameError.
Avoid hidden global dependencies
tax_rate = 0.18
def add_tax(amount):
return amount + amount * tax_rate
The function depends on a name outside its inputs. A notebook may contain an old tax_rate, making the result hard to reproduce.
Pass the dependency explicitly:
def add_tax(amount, tax_rate):
return amount + amount * tax_rate
A side effect changes something outside the returned value
Printing, modifying a supplied list, writing a file, and making a network request are side effects.
def add_tag(tags, tag):
tags.append(tag)
return tags
This changes the caller's list.
Create a copy when the contract should preserve input:
def with_added_tag(tags, tag):
updated_tags = tags.copy()
updated_tags.append(tag)
return updated_tags
Side effects are not always wrong
A function that saves a file must affect the outside world. The problem is an unexpected or undocumented effect. Name and document it clearly, and keep pure calculation separate where possible.
Practice
Given a function that reads discount_rate from a notebook cell and appends to a supplied list, identify both outside dependencies. Refactor it to receive the rate explicitly and return a copied list.
Takeaway
Local scope keeps temporary names inside the function. Explicit parameters reduce hidden dependencies. Side effects should be intentional, limited, and documented. Next, we will state function contracts with docstrings and basic type hints.
