What's covered so far (Week 2, Day 1), and what's still coming.
A block of code, packaged once under a name, that can be run again anywhere just by calling that name — instead of retyping or copy-pasting the same logic every time it's needed.
def greet():
print("Hello!")Writing this defines the function — it does NOT run it. The code inside only executes when you actually call it:
greet()Forgetting the () when calling, or expecting the code to run just because it's defined, is a common early mistake.
def greet_person(name):
print(f"Hello, {name}!")
greet_person("Hamza") # prints "Hello, Hamza!"
greet_person("Sara") # same function, different output, because different inputname is a parameter — a placeholder that receives whatever value gets passed in at call time. Same function body, different result each call, based on the input given.
print()— displays something in the terminal. Nothing is handed back to the program; once displayed, it's gone.return— hands a value back to wherever the function was called from, so it can be stored in a variable, used in further calculations, or printed by the caller.
def add(a, b):
return a + b
result = add(5, 3) # result now holds 8
print(result)
print(add(2, 3)) # or use it immediately, no variable needed — prints 5If a function has no return at all, calling it and trying to store the result gives you None:
def add_no_return(a, b):
print(a + b) # displays 7
result = add_no_return(3, 4)
print(result) # None — nothing was ever returned to storeEvery function call is completely independent. return sends its value directly to the exact spot where that specific call happened — it is NOT a shared slot that different calls or different functions write into and overwrite.
def add(a, b):
return a + b
x = add(2, 3) # x = 5
y = add(10, 20) # y = 30
print(x) # still 5 — completely unaffected by the second callOnce a function is defined, it's available anywhere in the rest of the program, not just where it was first used — inside a menu's elif chain, inside a loop, inside another function. Write the logic once; call it as many times and in as many places as needed, instead of duplicating the same calculation throughout the file.
def add(a, b):
return a + b
def subtract(a, b):
return a - b
if choice == "1":
result = add(num1, num2)
elif choice == "2":
result = subtract(num1, num2)This is the direct upgrade path for the calculator project — each menu option calls a focused, single-purpose function instead of writing the math inline.
Giving a parameter a fallback value so it's optional when calling:
def greet(name="friend"):
print(f"Hello, {name}!")
greet() # uses the default — "Hello, friend!"
greet("Hamza") # overrides it — "Hello, Hamza!"Where a variable "lives" and whether code outside a function can see it. A genuinely common source of confusing bugs — variables created inside a function normally don't exist outside it, and variables from outside aren't automatically changeable from inside a function without extra care.
Ways to let a function accept a flexible, unknown number of arguments, rather than a fixed, exact list of parameters.
Taking the actual calculator project and refactoring it to use one function per operation, called from the menu's elif chain — the direct, practical payoff of everything above, applied to real existing code.
Why .append(), .get(), etc. look similar to functions but are technically called "methods" — belonging to a specific object type, called with the dot syntax already used all through Week 1.
- Can I explain, out loud, the difference between defining and calling a function?
- Can I explain why
print()inside a function andreturninside a function behave differently when I try to store the result in a variable? - Do I understand why
returnfrom one function call doesn't affect or get overwritten by a different call to the same function?