Core Python · #4 of 11

Functions + Scope

Reusable logic and clean code

Why it matters

Functions keep your logic reusable, testable, and readable.

The idea

A function is a mini-program: input → processing → output. Default arguments turn one function into many; *args / **kwargs make it variadic. Scope follows LEGB: Local → Enclosing → Global → Built-in.

Try it

Default args + keyword args:

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

print(greet("Ada"))
print(greet("Linus", greeting="Hi"))
print(greet(greeting="Howdy", name="Margaret"))
not loaded

*args / **kwargs capture overflow positional and keyword arguments:

def describe(*things, **labels):
  for t in things:
      print("-", t)
  for k, v in labels.items():
      print(k, "=", v)

describe("apple", "banana", "cherry", colour="red", taste="sweet")
not loaded

Scope: a function sees outer names but cannot rebind them without nonlocal / global:

counter = 0
def inc():
  global counter
  counter += 1

inc(); inc(); inc()
print("counter:", counter)

def outer():
  x = 1
  def inner():
      nonlocal x
      x += 10
  inner()
  print("outer.x:", x)

outer()
not loaded

Function patterns by data type

A function's shape often follows the type it works on. These three patterns bridge straight into the data-structure lessons:

Quick check

Mini drills

Do's and don'ts

Common mistakes

Key takeaways