livepython.net
CHAPTER 15Python Functions
15.4  SCOPE

Python Variable Scope, Docstrings and Good Habits

Local Variables in Python

A variable made inside a function is a local variable: it exists only inside that function, and only while the function runs. The part of a program where a name can be used is called its scope.

Think of it like a whiteboard in a hotel room: you can write on it while you stay, and it's wiped when you check out. People down in the lobby can't read it.

PYTHONedit me
def make_total():
    total = 10 + 20
    print("Inside:", total)

make_total()
print("Outside:", total)
OUTPUT
Inside: 30
NameError: name 'total' is not defined

Don't be scared of this error! It's saying that outside the function, there's no total. It lived inside make_total(), and it was wiped when the function ended.

The rules

  • A variable you create inside a function is local to it.
  • Parameters are local too: they only exist inside the function.
  • Every call starts fresh. Local variables don't remember anything from the last call.
PYTHONedit me
def visit():
    count = 0
    count += 1
    print("Visits:", count)

visit()
visit()
OUTPUT
Visits: 1
Visits: 1

Each call makes a brand-new count, starting at 0. That's why it never reaches 2.

The fix: return the value

When the code outside needs a value from inside, return it, and store what comes back:

PYTHONedit me
def make_total():
    total = 10 + 20
    return total

total = make_total()
print("Outside:", total)
OUTPUT
Outside: 30

There are two variables called total here: one local, inside the function, and one outside. return carries the value from one to the other.

A variable made inside a function lives only there. Return it to use it outside.

your turnSpot the bug

Which line breaks?

One line stops this program. Tap it.
your turnPredict the output

What will this print?

def add_point(points): points += 1 return points print(add_point(5)) print(add_point(5))
Your turn! What will this code show on the screen?

Global Variables in Python

A variable made outside every function, at the left edge of your file, is a global variable. Every function can read it.

Think of it like the clock on a classroom wall: everyone can read the time, but nobody gets to set it from their desk.

PYTHONedit me
shop = "Sunny's Shop"

def welcome():
    print(f"Welcome to {shop}!")

welcome()
OUTPUT
Welcome to Sunny's Shop!

Assigning inside makes a new local variable

If a function assigns to a name, Python makes a new local variable with that name. The global one isn't touched:

PYTHONedit me
score = 0

def play():
    score = 100
    print("Inside:", score)

play()
print("Outside:", score)
OUTPUT
Inside: 100
Outside: 0

Two different variables share the name score. The one inside lives in the function; the one outside stays 0.

Avoid: changing a global with +=

PYTHONedit me
count = 0

def add_one():
    count += 1

add_one()
OUTPUT
UnboundLocalError: cannot access local variable 'count' where it is not associated with a value

Every error is a clue! Because the function assigns to count, Python treats count as local in the whole function. And that local count has no value yet, so count + 1 can't be worked out.

The rules

Inside a function, you…What happens
read a globalworks
assign to the same namemakes a new local variable; the global stays the same
change it with +=UnboundLocalError

Python does have a keyword, global, that lets a function change a global variable. Most programmers avoid it: when any function can change a value, it gets very hard to find out who changed it. The next lesson shows the better way.

Functions can read global variables, but assigning inside makes a new local one.

your turnPredict the output

What will this print?

level = 1 def level_up(): level = 2 level_up() print(level)
Your turn! What will this code show on the screen?
your turnPick the right idea

A function only reads a global variable called tax_rate. What happens?

Think about it, then pick one.

Pass Values In, Return Values Out

The clean way to share data with a function is simple: give it what it needs as arguments, and get the answer back with return. Then the function depends only on its inputs, never on variables outside it.

Think of it like a juicer: fruit goes in at the top, and juice comes out of the spout. It doesn't reach into your fridge to grab things on its own.

Avoid: a function that uses a global

PYTHONedit me
count = 0

def add_one():
    count += 1

add_one()
print(count)
OUTPUT
UnboundLocalError: cannot access local variable 'count' where it is not associated with a value

Good: pass it in, return it out

PYTHONedit me
def add_one(count):
    return count + 1

count = 0
count = add_one(count)
count = add_one(count)
print(count)
OUTPUT
2

The function gets the value as an argument and returns the new one. The code outside decides where to store it.

Why this is better

  • Easy to test. Call add_one(5), add_one(99): the same input always gives the same answer.
  • Easy to reuse. The function works for any value, not only one particular variable.
  • No surprises. Nothing outside changes unless you store the result yourself.

A real example with input:

PYTHONedit me
def apply_discount(price, percent):
    return price - price * percent / 100

price = float(input())
final = apply_discount(price, 10)
print(f"To pay: {final:.2f}")
OUTPUT
To pay: 225.00

apply_discount() doesn't read the input or print anything. It only does the maths. Reading and printing happen outside, in the main part of the program.

Common beginner doubt: "Can a parameter have the same name as a variable outside?" Yes, like count above. The parameter is a separate, local variable. It only starts with the same value because you passed it in.

Pass the values a function needs as arguments, and return its answer.

your turnFix the code

Fix the program so it prints: 1

It should print: 1

count = 0

def add_one():
    count += 1

add_one()
print(count)
This code does not work yet. Fix it, then press Run.

Python Docstrings: Describe Your Function

A docstring is a string in triple quotes on the first line of a function's body. It says what the function does. In the Comments chapter (chapter 6), you met docstrings at the top of a file. Now you'll write them for your functions.

Think of it like the label on a jar: you know what's inside without opening it.

PYTHONedit me
def area(length, width):
    """Return the area of a rectangle."""
    return length * width

print(area(3, 4))
OUTPUT
12

The rules

  • It's the first line of the body, indented like the body.
  • Use three double quotes: """…""".
  • Start with one short sentence that says what the function does: "Return the area…", "Print a menu…".
  • For a longer docstring: the short sentence, an empty line, then more details, like what each parameter means.
PYTHONedit me
def bill(price, qty, tip=10):
    """Return the total bill.

    price is the cost of one item, qty how many,
    and tip a percent added on top (10 if left out).
    """
    return price * qty * (100 + tip) / 100

print(bill(50, 2))
OUTPUT
110.0

Python keeps your docstring

Python stores the docstring with the function, under the special name __doc__. Code editors show it when you point at the function's name, so anyone using it can read what it does:

PYTHONedit me
def area(length, width):
    """Return the area of a rectangle."""
    return length * width

print(area.__doc__)
OUTPUT
Return the area of a rectangle.

Docstring or comment?

UseFor
a docstringwhat the function does, for people who call it
a # commenthow a tricky line works, for people who read the code

Common beginner doubt: "Does every function need a docstring?" Tiny, obvious functions can do without one. But a one-line docstring costs you five seconds and helps everyone, including you next month.

A docstring is the first line of the body, in triple quotes, saying what the function does.

your turnPick the right idea

Where does a function's docstring go?

Think about it, then pick one.
your turnPredict the output

Remember sets?

colors = {"red", "blue", "red"} print(len(colors))
Your turn! What will this code show on the screen?

Good Habits for Writing Functions

A few good habits make your functions easy to read, test and reuse. They're not rules Python checks, but every good programmer follows them.

Think of it like a toolbox: a screwdriver does one job well. A tool that tries to be a hammer, a saw and a torch at once does every job badly.

Five habits

HabitExample
One job per functionaverage() only works out an average
A verb name that says the jobget_total, is_valid, print_report
Values in as parameters, answers out with returnno global variables
A docstring as the first line"""Return the average of a list."""
Short: if it doesn't fit on the screen, split itthree small functions beat one huge one

A program built from small functions

PYTHONedit me
def average(marks):
    """Return the average of a list of marks."""
    return sum(marks) / len(marks)

def grade(avg):
    """Return a letter grade for an average mark."""
    if avg >= 75:
        return "A"
    if avg >= 50:
        return "B"
    return "C"

def print_report(name, marks):
    """Print one line about a student."""
    avg = average(marks)
    print(f"{name}: {avg:.1f} ({grade(avg)})")

print_report("Sunny", [80, 90, 70])
print_report("Rocky", [60, 65, 70])
OUTPUT
Sunny: 80.0 (A)
Rocky: 65.0 (B)

Each function does one job: average() and grade() work something out and return it; print_report() shows the result. You can test grade(74) on its own, and reuse average() in any other program.

Avoid: one function that does everything

A single function that reads the input, works out the average, picks a grade and prints it all is hard to test. To check the grades, you'd have to type marks in every time. Split the working out (return) from the showing (print).

Common beginner doubt: "Should every function return instead of print?" No. A function whose job is to show something, like print_report(), prints. A function that works something out returns. Keep those two jobs in separate functions.

In the next chapter, you'll learn PEP 8, Python's style guide, with even more tips for neat code.

One job, a clear verb name, values in and answers out, and a docstring on top.

your turnPick the right idea

Which is the best name for a function that returns True when a password is long enough?

Think about it, then pick one.
your turnType the output

Type what this prints

def average(marks): """Return the average of a list of marks.""" return sum(marks) / len(marks) print(average([10, 20, 30]))
Read the code line by line, then type the output exactly.

Practice: Scope

Solve these to lock in what you learned in this topic. Each one runs in your browser.

  1. 138.Fix the NameError in a Python FunctionEasySolve
  2. 139.Python Program to Make a Marks Report Using FunctionsHardSolve