Part of Python for Beginners

Python Functions Tutorial - def, return, scope, keyword arguments | Beginner #11

Sandy LaneSandy Lane

Video: Python Functions Tutorial - def, return, scope, keyword arguments | Beginner #11 by Taught by Celeste AI - AI Coding Coach

Take the quiz on the full lesson page
Test what you've read · interactive walkthrough

Python Functions: def, return, scope, keyword arguments

def name(params): defines. return value returns. Default parameters with =. Keyword arguments at the call site. Docstrings between triple-quotes are the standard documentation.

Functions package up logic for reuse. Python's function syntax is more flexible than most languages — defaults, keyword args, multiple returns.

def: defining a function

def greet():
  print("Hello, World!")

greet()
greet()

def name(): creates a function. The body is indented. Call with name().

For functions with arguments:

def greet_name(name):
  print(f"Hello, {name}!")

greet_name("Alice")
greet_name("Bob")

return value

def add(a, b):
  return a + b

result = add(3, 5)
print(f"3 + 5 = {result}")     # 8
print(f"10 + 20 = {add(10, 20)}")

return value exits the function and returns value. Without return, the function returns None.

For early exit:

def safe_divide(a, b):
  if b == 0:
    return None
  return a / b

Multiple return statements are fine.

Multiple return values

def divmod_op(a, b):
  return a // b, a % b   # implicitly a tuple

q, r = divmod_op(17, 5)
# q = 3, r = 2

Return a tuple; caller unpacks. Standard Python idiom.

Default arguments

def greet(name, greeting="Hello"):
  print(f"{greeting}, {name}!")

greet("Alice")              # Hello, Alice!
greet("Alice", "Hi")        # Hi, Alice!
greet("Alice", greeting="Hey")   # Hey, Alice! (keyword)

name=value in the parameter list provides a default. Caller can override or skip.

Defaults must come after non-defaults:

def f(a, b=2): pass    # OK
def f(a=1, b): pass    # SyntaxError

Mutable default trap

def append_to(item, lst=[]):
  lst.append(item)
  return lst

print(append_to(1))   # [1]
print(append_to(2))   # [1, 2] — same list reused!

The default [] is created once, when the function is defined. Subsequent calls share it.

The fix: use None:

def append_to(item, lst=None):
  if lst is None:
    lst = []
  lst.append(item)
  return lst

Standard pattern. Always avoid mutable defaults.

Keyword arguments

def make_person(name, age, city="Unknown"):
  return {"name": name, "age": age, "city": city}

# Positional
make_person("Alice", 30)

# Keyword
make_person(name="Alice", age=30, city="Portland")

# Mixed
make_person("Alice", age=30, city="Portland")

At the call site, name=value is keyword-style — order doesn't matter, only the name.

For functions with many parameters, keyword args make calls self-documenting.

Docstrings

def area(width, height):
  """Calculate area of a rectangle.

  Args:
    width: The width.
    height: The height.

  Returns:
    The area as int or float.
  """
  return width * height

print(area.__doc__)    # the docstring
help(area)              # also shows it

A string as the first statement in a function is its docstring. Tools like help(), IDE tooltips, and pydoc use it.

Conventions: Google style, NumPy style, reST. Pick one for your project.

Scope: local, enclosing, global, builtin

x = 10        # global

def outer():
  y = 20      # enclosing
  def inner():
    z = 30    # local
    print(x, y, z)
  inner()

outer()
# 10 20 30

Python's scope is LEGB: - Local — inside the current function. - Enclosing — outer function (for nested functions). - Global — module top-level. - Builtin — print, len, etc.

Names are looked up from L outward.

global and nonlocal

counter = 0

def increment():
  global counter   # without this, counter = is a local assignment
  counter += 1

increment()
increment()
print(counter)   # 2

global x says "x refers to the global, not a new local."

For nested functions:

def outer():
  x = 0
  def inner():
    nonlocal x   # refers to outer's x
    x += 1
  inner()
  print(x)   # 1

nonlocal for the enclosing function's local. global for module-level.

Both are usually code smells — pure functions are easier to reason about.

A grade calculator

def calculate_average(scores):
  return sum(scores) / len(scores)

def get_letter_grade(average):
  if average >= 90: return "A"
  elif average >= 80: return "B"
  elif average >= 70: return "C"
  elif average >= 60: return "D"
  else: return "F"

scores = [85, 90, 78, 92, 88]
avg = calculate_average(scores)
grade = get_letter_grade(avg)
print(f"Average: {avg:.1f}, Grade: {grade}")

Two small functions, composable. Each does one thing.

Type hints (preview)

def add(a: int, b: int) -> int:
  return a + b

Optional type annotations. Lesson 29 covers them.

First-class functions

def double(x): return x * 2
def triple(x): return x * 3

operations = [double, triple]
for op in operations:
    print(op(5))   # 10, then 15

Functions are values — store in lists, dicts, pass as arguments. Lambda functions (lesson 13) and decorators (lesson 23) build on this.

Common stumbles

Mutable default argument. def f(lst=[]) — same list reused. Use None.

Missing return. Function returns None silently. Make sure to return when you need a value.

Indentation errors. Mix of tabs and spaces. Pick one.

Forgetting parens at call. greet without () is the function object, not the call.

Modifying global without global keyword. Local assignment shadows. Use global x to modify.

Too many positional args. For functions with > 3 args, prefer keyword for clarity.

What's next

Lesson 12: ** args and kwargs*. Variable-arity functions; the foundation for decorators and flexible APIs.

Recap

def name(params): body. return value for output (default None). Default args: def f(x, y=10); avoid mutable defaults. Keyword args at call site: f(x=1, y=2). Docstrings: triple-quoted string as first statement. Scope: LEGB (Local, Enclosing, Global, Builtin); global/nonlocal to assign upward. Functions are first-class — store, pass, return.

Next lesson: args and *kwargs.

Ready? Take the quiz on the full lesson page →
Test what you've learned. Watch the lesson and try the interactive quiz on the same page.