CS 111 › Lesson 5 of 12

Functions & Scope

Lesson 5 · CS 111: Programming I — Python · OKSTEM College

Defining & Calling Functions

A function is a reusable named block of code. You define it once, call it many times.

def function_name(parameter1, parameter2): """Docstring: what this function does.""" # body return result # optional # Call it: output = function_name(arg1, arg2)

Parameters vs Arguments: Parameters are the variable names in the def line. Arguments are the actual values you pass when calling the function. They're often used interchangeably in conversation.

Return Values

A function can send a value back to the caller using return. Without it, the function returns None.

Example - Area of a circle

import math def circle_area(radius): """Return the area of a circle given its radius.""" return math.pi * radius ** 2 a = circle_area(5) print(f"Area: {a:.2f}") # Area: 78.54 # You can return multiple values (as a tuple) def min_max(numbers): return min(numbers), max(numbers) lo, hi = min_max([4, 1, 9, 2]) print(lo, hi) # 1 9

Scope: Local vs Global

Variables created inside a function are local - they only exist while the function runs. Variables outside functions are global.

x = 10 # global def demo(): x = 99 # local - does NOT change the global x print(x) # 99 demo() print(x) # still 10

Avoid globals: Passing values via parameters and return values makes code easier to test and reason about. Using global keyword to modify globals from inside functions is a sign of poor design.

Default & Keyword Arguments

def greet(name, greeting="Hello"): print(f"{greeting}, {name}!") greet("Alice") # Hello, Alice! greet("Bob", "Hi") # Hi, Bob! greet(greeting="Hey", name="Carol") # Hey, Carol!

Default arguments make parameters optional. Keyword arguments let you specify them by name in any order.

Practice Problems

Problem 1 - is_palindrome()

Write a function that returns True if a string reads the same forwards and backwards.

def is_palindrome(s): s = s.lower().replace(" ", "") return s == s[:-1]

s[::-1] reverses a string using slice notation (start:stop:step, with step -1 going backwards). Lowercasing and removing spaces handles "A man a plan a canal Panama".

Problem 2 - celsius_to_fahrenheit() with default precision

Write a function that converts Celsius to Fahrenheit, with an optional decimals parameter (default 1) controlling how many decimal places to return.

def celsius_to_fahrenheit(c, decimals=1): f = c * 9/5 + 32 return round(f, decimals) print(celsius_to_fahrenheit(100)) # 212.0 print(celsius_to_fahrenheit(37, 2)) # 98.6

Problem 3 - factorial() using recursion

Write a recursive function that computes n! (n factorial). Recall: 5! = 5 * 4 * 3 * 2 * 1 = 120. Base case: 0! = 1.

def factorial(n): if n == 0: # base case return 1 return n * factorial(n - 1) # recursive case print(factorial(5)) # 120

factorial(5) calls factorial(4) which calls factorial(3)... down to factorial(0) which returns 1. Then each call multiplies back up: 1 * 1 = 1, 2*1=2, 3*2=6, 4*6=24, 5*24=120.

Knowledge Check

What does a function return if it has no return statement?

0 is a valid integer; the default is None.
Correct - implicit return value is None.
Empty string '' is different from None.
False is a boolean; the default is None.
Quick Recap

In Python, a function with no return statement (or just return) implicitly returns None, not 0.

Quick Recap

None is Python's null value. An empty string '' has type str. Functions with no return give None.

Quick Recap

None is Python's way of saying 'no value'. It's distinct from False, 0, or ''.

Where does a local variable exist?

That describes a global variable.
Correct - local scope is function-level.
if blocks don't create a new scope in Python.
Local means inside the function, not the module.
Quick Recap

Local variables only live inside the function that created them. They're destroyed when the function returns.

Quick Recap

Unlike some languages, Python if/for/while blocks do NOT create a new scope. Only functions (and classes/modules) create scope boundaries.

Quick Recap

Local variables belong to the function's scope. Multiple functions can each have their own local variable named 'x' without conflict.

Which call uses a keyword argument?

This is a positional argument.
Correct - name= is the keyword.
This passes no arguments at all.
* unpacks a list as positional arguments.
Quick Recap

Positional arguments are matched by position. Keyword arguments explicitly name the parameter: greet(name='Alice').

Quick Recap

greet() with empty parens passes nothing. A keyword argument names the parameter explicitly.

Quick Recap

*args unpacks a sequence as positional arguments. Keyword arguments use name=value syntax.

What is the output? def f(x, y=2): return x * y then print(f(3))

y defaults to 2, so 3 * 2 = 6.
Correct - x=3, y defaults to 2, product is 6.
y has a default so it's optional.
2 is y's value but the function multiplies x*y.
Quick Recap

y has a default value of 2. Calling f(3) means x=3, y=2. Result: 3*2=6.

Quick Recap

Default arguments make parameters optional. y=2 means you don't have to pass y.

Quick Recap

The function returns x*y = 3*2 = 6, not just y's value.

A recursive function must have:

Recursion doesn't require globals.
Recursion and loops are alternative approaches.
Correct - without a base case the function calls itself forever.
Factorial works with one parameter.
Quick Recap

Recursion works through the call stack. No global variable is needed.

Quick Recap

Recursion replaces loops - you don't need both. Recursion calls itself instead of using a loop.

Quick Recap

Recursive functions can have any number of parameters. The essential requirement is a base case.