Python
CompleteFunctions
Study Notes
Based on your teacher's slides · Topics 2.1 – 2.7
Includes common mistakes to avoid
2.1 Introduction to Functions
A function is a named group of statements that performs a specific task. Instead of repeating code, you write
it once and call it whenever needed. Functions are also called sub-routines, methods, procedures, or
subprograms.
Why use functions?
Advantage Explanation
Easier handling Only one small part of the program is worked on at a time.
Reduced lines of code Common code is written once and called from anywhere.
Easy updating Change the logic in one place — reflected everywhere.
Module & Library
• Module — a .py file that stores a set of functions.
• Modularization — the approach of breaking a program into modules.
• Library — commonly used modules with generic-purpose code (e.g. math, random).
2.2 Functions in Python
2.2.1 Built-in Functions
Already provided by Python. You have been using these all along:
print("hello") # built-in
len("hello") # built-in
int("5") # built-in
2.2.3 User-Defined Functions — Syntax
def function_name([parameters]):
statements
[return value]
Key rules:
• def keyword marks the start of the function header.
• Function name must be unique and follow identifier naming rules.
• A colon : ends the function header.
• Body is indented — all statements inside must be indented equally.
• return is optional. A function must be called/invoked to run.
Simple Example
def greet():
print('Hello!')
print('Welcome to Python.')
greet() # calling the function
✓ The function does nothing until you call it. Defining is not running.
2.3 How a Function Returns a Value
Use the return keyword to send a result back to the caller. Once Python hits return, the function exits
immediately — any code after return is unreachable.
def square(n):
return n * n
print('I never run!') # unreachable!
result = square(5)
print(result) # 25
Three ways to use a return value
r = square(4) # store in variable → r = 16
print(square(3)) # use in print → 9
total = square(2) + 10 # use in expression → 14
Returning multiple values
Python can return more than one value — they are automatically packed into a tuple.
def add10(x, y, z):
return x+10, y+10, z+10
# Store as tuple:
result = add10(1, 2, 3) # (11, 12, 13)
# Unpack into variables:
a, b, c = add10(1, 2, 3) # a=11, b=12, c=13
2.4 Parameters and Arguments
Term Also called Where Example
Parameter Formal argument In function definition def area(r):
Argument Actual argument In function call area(5)
2.4.1 & 2.4.2 The 4 Types of User-Defined Functions
Type 1 — No argument, no return (Void function)
def welcome():
print('Namaste!')
welcome() # Output: Namaste!
Type 2 — Arguments, no return
def table(num):
for i in range(1, 11):
print(num, 'x', i, '=', num * i)
table(5) # prints the 5 times table
Type 3 — Arguments with return
def cube(n):
return n * n * n
answer = cube(3)
print(answer) # 27
Type 4 — No argument, with return
def getGreeting():
return 'Good morning!'
msg = getGreeting()
print(msg) # Good morning!
2.5 Types of Arguments
1. Positional Arguments
Matched by position — order matters!
def divide(a, b):
print(a / b)
divide(10, 2) # 5.0
divide(2, 10) # 0.2 ← completely different result!
2. Default Arguments
A parameter gets a preset value used when no argument is passed.
def greet(name, msg='Hello'):
print(msg, name)
greet('Aryan') # Hello Aryan (uses default)
greet('Aryan', 'Hi') # Hi Aryan (overrides default)
■ Default arguments must always come AFTER non-default arguments.
def f(a, b=5, c=10): # VALID
def f(a, b=5, c): # INVALID — non-default after default!
3. Keyword (Named) Arguments
Pass arguments by name — order does not matter!
def intro(name, age):
print(name, 'is', age, 'years old')
intro(age=17, name='Aryan') # order swapped — still works!
4. Variable Length Arguments
Use *args for variable positional arguments, **kwargs for variable keyword arguments.
def total(*nums):
print(sum(nums))
total(1, 2, 3) # 6
total(10, 20, 30, 40) # 100
Legal / Illegal Combinations — def Average(n1, n2, n3=100)
Function Call Legal? Reason
Average(n1=20, n2=40, n3=80) ✓ Legal All named — fine
Average(n3=10, n2=7, n1=100) ✓ Legal Keyword args can be in any order
Average(100, n2=10, n3=15) ✓ Legal Positional before keyword
Average(n3=70, n1=90, 100) ✗ Illegal Positional after keyword not allowed
Average(100, n1=23, n2=1) ✗ Illegal n1 gets two values
2.6 Scope of Variables
Scope means where in the program a variable can be seen and used. Think of it like rooms in a house —
a bedroom variable stays in the bedroom.
Global Scope
Declared outside all functions. Readable from anywhere in the program.
city = 'Jammu' # global
def show():
print(city) # OK — can read global
show() # Jammu
print(city) # Jammu
Local Scope
Declared inside a function. Only exists while that function is running. Destroyed after.
def calc():
result = 50 # local
print(result) # OK inside
calc() # 50
print(result) # NameError — result doesn't exist out here!
Same name in both scopes
Python always prefers the local one inside the function. The global one is untouched.
x = 'global'
def check():
x = 'local' # completely separate variable
print(x) # local
check() # local
print(x) # global (unchanged)
Modifying a global variable inside a function
■ Simply reading a global is fine. But to MODIFY it inside a function, you MUST use the global
keyword — and it must come FIRST.
count = 0
def increment():
global count # declare FIRST
count += 1 # now modify
increment()
increment()
print(count) # 2
Lifetime of a Variable
Variable Type Born Dies
Global When program starts When program ends
Local When its function is called When its function finishes
LEGB Rule — Name Resolution Order
Whenever Python sees a variable name, it searches in this order and stops at first match:
Level Stands for Description
L Local Inside the current function
E Enclosing Outer function (for nested functions)
G Global Top level of the program
B Built-in Python's own names: print, len, range...
x = 'global'
def outer():
x = 'enclosing'
def inner():
print(x) # E → 'enclosing'
inner()
print(x) # local outer → 'enclosing'
outer()
print(x) # G → 'global'
✓ If Python exhausts all 4 levels and finds nothing → NameError.
2.7 Flow of Execution with Function Calls
Python reads top to bottom. When it hits a function call it jumps into the function, runs it completely, then
returns to where it left off.
def sayHi():
print('Hi from function!')
print('Before call')
sayHi()
print('After call')
# Output:
# Before call
# Hi from function!
# After call
The main() pattern
Optional in Python but good practice. The idiom below ensures the code only runs when the file is executed
directly — not when imported as a module.
def area(l, b):
return l * b
def main():
l = int(input('Enter Length'))
b = int(input('Enter Breadth'))
print('Area =', area(l, b))
if __name__ == '__main__':
main()
Recursion
A function that calls itself. Must have a base condition — a stopping point — otherwise it runs forever and
crashes (stack overflow).
def factorial(num):
if num == 1: # base condition
return 1
else:
return num * factorial(num - 1) # recursive call
print(factorial(5)) # 120
How factorial(5) unwinds:
5 * factorial(4)
4 * factorial(3)
3 * factorial(2)
2 * factorial(1)
return 1
return 2
return 6
return 24
return 120
Property Detail
Base condition Required — stops recursion. Written using if.
Execution order Uses a stack — solves large → small, unwinds small → large.
Memory More than loops — each call allocates memory for local variables.
Property Detail
Speed Less efficient than loops.
Best for Tree, Graph and complex data structure problems.
Common Mistakes to Avoid ■
These are the exact mistakes made during this study session — memorise them!
Mistake 1 — return print() gives None
# WRONG
def greet(name):
return print('hello!', name) # print() returns None!
n = greet('Ikram')
print(n) # None
■ print() is a function that displays text and returns None. Wrapping it in return gives you None, not
the text.
# CORRECT — option 1: just print
def greet(name):
print('hello!', name)
# CORRECT — option 2: return a string
def greet(name):
return 'hello! ' + name
Mistake 2 — Forgetting return altogether
# WRONG
def greet(name):
'hello!', name # creates a tuple, immediately discards it!
print(greet('Ikram')) # None
■ A bare expression on its own line does nothing. Without return, the function returns None
automatically.
# CORRECT
def greet(name):
return 'hello! ' + name
Mistake 3 — Two *args parameters
# WRONG
def who(*name, *age): # SyntaxError!
...
■ You can only have ONE *args parameter. It collects ALL positional arguments. Use **kwargs for
keyword arguments.
# CORRECT — one *args and one **kwargs
def who(*names, **details):
print(names)
print(details)
who('Burhan','Bota', age1=19, age2=20)
Mistake 4 — Duplicate keyword arguments in a call
# WRONG
who(name='Burhan', name='Bota') # SyntaxError — name passed twice!
■ You cannot pass the same keyword argument more than once in a single call.
Mistake 5 — global keyword not at the top
# WRONG
def who():
print(n) # using n...
global n # ...before declaring global — SyntaxError!
n = 'nolan'
■ The global declaration must come BEFORE any use of that variable in the function.
# CORRECT
def who():
global n # declare FIRST
print(n) # then use
n = 'nolan'
Mistake 6 — Default argument before non-default
# WRONG
def f(a, b=5, c): # SyntaxError!
...
■ Default arguments must always come AFTER all non-default arguments.
# CORRECT
def f(a, b, c=5): # c has default, comes last
...
Mistake 7 — Expecting to modify global without global keyword
# WRONG
count = 0
def increment():
count += 1 # UnboundLocalError!
■ Python sees count += 1 as creating a local variable, but it's unassigned when read on the right side.
# CORRECT
def increment():
global count
count += 1
Mistake 8 — Accessing local variable outside its function
def calc():
result = 50
calc()
print(result) # NameError — result is local, it's gone!
■ Local variables only exist while their function is running. Return the value if you need it outside.
def calc():
result = 50
return result # send it out
r = calc()
print(r) # 50
Quick Revision Summary
Concept Key Point
def Keyword to define a function
Calling a function function_name() — must call to execute
return Sends value back; exits function immediately
return print(...) Always gives None — don't do this
No return statement Function automatically returns None
Parameter (formal) Variable in function definition
Argument (actual) Value passed in function call
Default argument Must come after non-default arguments
Keyword argument Can be passed in any order by name
*args Collects positional args into a tuple (only one allowed)
**kwargs Collects keyword args into a dict
Global variable Outside all functions — visible everywhere
Local variable Inside a function — invisible outside
global keyword Required to MODIFY a global inside a function — must be first
LEGB rule Local → Enclosing → Global → Built-in
NameError Variable not found in any of the 4 LEGB levels
Lifetime — global Entire program run
Lifetime — local Only while its function executes
Recursion base case Required — without it recursion is infinite
Void function No return value (returns None implicitly)
Good luck on your exam tomorrow! — Study notes generated from your teacher's PDF