VM-LEARNING /class.xii ·track.cs ·ch-1-2 session: 2026_27
$cd ..

~/Functions

root@vm-learning ~ $ open ch-1-2
UNIT 1 ▪ CHAPTER 2
02
Functions
Types · Definition & Call · Parameters · Arguments · Return · Scope · Worked Programs
A function is a named block of code that performs a specific task. You write it once and call it whenever you need it, instead of repeating the same lines all over your program.
Real-life analogy. Think of a function like a recipe in a cookbook. The recipe for “tea” is written just once; every morning you simply say “make tea for 2 cups” and it works. def is the act of writing the recipe; calling the function is the act of using it.

2.1 Why do we need Functions?

Imagine you are writing a report-card program. You need to calculate the percentage for Asha, Rahul, Riya and 47 other students. Without functions, you would have to type the same formula total/5 fifty times — and if the formula ever changes, you’d have to edit fifty places. With a function called percentage(), you write the formula once and call it fifty times.

Four big benefits of functions:
  • Re-use — write the logic once, call it many times.
  • Readability — a call like area(l, b) reads like plain English.
  • Easy maintenance — fix or improve the code in one place only.
  • Decomposition — break a big problem into small, independent pieces.

2.2 Types of Functions in Python

Every function you call in Python belongs to one of three families:

TypeWhere it comes fromWho wrote itExample
Built-inPart of Python itself — always availablePython authorsprint(), len(), input()
ModuleDefined inside a module you importLibrary authorsmath.sqrt(), random.randint()
User-definedDefined by you using defYou, the programmerdef percentage(total): …

2.2.1 Built-in Functions

Python comes with about seventy ready-made functions. You don’t have to import anything — they are always ready.

print(len("Python")) # built-in: len print(max(5, 2, 9)) # built-in: max n = int(input()) # two built-ins on one line

2.2.2 Module Functions

Functions that live inside modules (organised libraries of related code). You must import the module first.

import math print(math.sqrt(25)) # 5.0 print(math.factorial(5)) # 120 from random import randint print(randint(1, 6)) # a dice roll

2.2.3 User-defined Functions (UDF)

Whenever the problem needs logic that Python doesn’t already provide, you write your own function. These are the focus of the rest of this chapter.

2.3 Your First User-defined Function

2.3.1 Syntax of a function definition

def function_name(parameter1, parameter2, ...): """optional docstring — what does this function do?""" # body — the statements that do the work return value # optional
Five parts of every function:
  1. def — the keyword that starts a definition.
  2. function name — follows the same rules as any identifier.
  3. parameters in parentheses — zero or more, separated by commas.
  4. colon at the end of the header, followed by an indented body.
  5. return (optional) — sends a value back to the caller.

2.3.2 A tiny working example

def greet(name): print("Hello,", name, "!") greet("Asha") greet("Rahul")
Hello, Asha ! Hello, Rahul !

2.3.3 Defining vs. Calling — an important distinction

Definition (using def) only creates the function. Nothing runs yet — Python just remembers the recipe. The body runs only when the function is called by name, with () after it.
def say_hi(): # DEFINITION — body does NOT run print("Hi there!") # nothing printed yet say_hi() # CALL — body runs now say_hi() # CALL again — body runs a second time
Hi there! Hi there!

2.3.4 Docstring — documenting your function

A triple-quoted string placed as the very first line of the body is called a docstring. It becomes the function’s help text.

def area_rect(l, b): """Return the area of a rectangle with sides l and b.""" return l * b help(area_rect)

2.4 Arguments and Parameters

2.4.1 Parameter vs. Argument — what’s the difference?

ParameterArgument
Where it appearsInside the def () lineInside the call ()
What it isA variable name — a placeholderA real value being supplied
Also calledFormal parameterActual parameter
def greet(name): # 'name' is the PARAMETER print("Hello", name) greet("Asha") # "Asha" is the ARGUMENT
Quick mnemonic — “Parameter is the Placeholder · Argument is the Actual value”.

2.4.2 Positional Arguments

When you call the function, Python matches arguments to parameters by position — the first argument fills the first parameter, the second fills the second, and so on.

def intro(name, age): print(name, "is", age, "years old") intro("Asha", 17) # name="Asha", age=17 intro(17, "Asha") # name=17, age="Asha" ← WRONG ORDER!
Asha is 17 years old 17 is Asha years old
Positional arguments are the simplest but the most error-prone — if you pass them in the wrong order, Python will not complain, it will just produce a wrong result.

2.4.3 Keyword Arguments

To avoid ordering mistakes, you can write parameter=value in the call. Order no longer matters.

def intro(name, age): print(name, "is", age, "years old") intro(name="Asha", age=17) # same as before intro(age=17, name="Asha") # ORDER DOESN'T MATTER now
Asha is 17 years old Asha is 17 years old

2.4.4 Default Arguments

Sometimes most calls use the same value for a parameter. You can give it a default — callers may then omit it.

def greet(name, message="Hello"): # 'message' has a default print(message, name) greet("Asha") # uses default: message="Hello" greet("Rahul", "Namaste") # overrides the default
Hello Asha Namaste Rahul
Rule: parameters without a default must be listed before parameters with a default. The following is a SyntaxError:
def bad(x=10, y): # ❌ non-default argument follows default return x + y

2.4.5 Mixing positional, keyword & default — the golden rule

In one call you can combine all three, but the order inside the call must be:

  1. Positional arguments first
  2. Keyword arguments after that
def student(name, cls, section="A", house="Blue"): print(name, cls, section, house) student("Asha", 12) # ✅ defaults used student("Rahul", 12, "B") # ✅ positional override student("Riya", 12, section="C", house="Red") # ✅ mixed student(cls=12, name="Ankit") # ✅ all keyword student("Mohan", house="Green", 12) # ❌ positional after keyword

2.5 The return Statement

So far our functions only printed things. A more powerful pattern is a function that sends back a value — so the caller can store it in a variable, pass it to another function, or use it in an expression.

2.5.1 A function that returns one value

def square(n): return n * n result = square(7) # stores 49 in 'result' print(result) # 49 print(square(5) + square(6)) # 25 + 36 = 61
As soon as Python executes return, the function stops immediately — any code below return is never reached.

2.5.2 A function that returns multiple values

Write the values separated by commas after return; Python packs them into a tuple. The caller unpacks with multiple variables on the left of =.

def min_max(nums): return min(nums), max(nums) # returns a tuple low, high = min_max([23, 45, 12, 78, 56]) print("low =", low, " high =", high)
low = 12 high = 78

2.5.3 A function that returns nothing — None

If a function has no return (or writes just return with no value), it returns the special value None.

def greet(name): print("Hi", name) # no return statement x = greet("Asha") print(x) # None
Hi Asha None

2.5.4 return vs print — the classic confusion

Beginners mix these up all the time!
  • print(x)shows the value on screen, but the function still returns None.
  • return xsends the value back to the caller; the caller can do anything with it (store, print, use in an expression).
def square_print(n): print(n * n) # just prints def square_return(n): return n * n # gives back the value a = square_print(5) # prints 25, but a is None b = square_return(5) # b is 25 — usable print(b + 100) # 125 (works) print(a + 100) # TypeError — can't add None + int

2.6 Flow of Execution

Python executes the file top-to-bottom. When it meets a def, it remembers the function but does NOT run the body yet. The body runs only when the function is called. After the call finishes, control returns to the line that called it.

Trace this program carefully:
def cube(n): x = n ** 3 # step 3 return x # step 4 print("Start") # step 1 result = cube(4) # step 2 (jump into cube) print(result) # step 5 print("End") # step 6
Start 64 End
Memory model. Every call creates a fresh stack frame holding that call’s parameters and local variables. When the function returns, the frame is destroyed and the variables disappear — that’s why a local variable does not survive outside the function.

2.7 Scope of a Variable

Scope is the region of code in which a variable name is visible. Python has two main scopes you must know for CBSE: local (inside a function) and global (outside every function).
Global vs Local — a picture. GLOBAL SCOPE (the whole file) country = "India" def greet(name): LOCAL SCOPE of greet() message = "Hello"   # local to greet() print(message, name, "from", country) (can read global 'country', but 'message' cannot be seen outside) greet("Asha")

2.7.1 Local Scope

A variable created inside a function body exists only while that function is running. Trying to access it outside raises NameError.

def show(): x = 10 # local to show() print(x) # 10 show() print(x) # NameError: name 'x' is not defined

2.7.2 Global Scope

Variables defined at the top level of the file are global. Any function can read them.

country = "India" # global variable def who(): print("I live in", country) # reading global — OK who() # I live in India print(country) # I live in India — still there

2.7.3 The LEGB rule — name lookup order

When Python sees a name inside a function, it searches four scopes in this order:

  1. Local — the current function
  2. Enclosing — surrounding function (nested functions)
  3. Global — top level of the module
  4. Built-in — names like print, len, range

The first match wins.

2.7.4 The global keyword

A function can read a global variable but cannot reassign it unless you declare global.

count = 0 # global def increment(): count = count + 1 # ❌ UnboundLocalError — tries to create local increment()

Why the error? Because the moment Python sees count = ... inside the function, it marks count as a local variable for this function — but then count + 1 tries to read that local value before it was set.

Two ways to fix it:

# Way 1 — declare that 'count' refers to the GLOBAL one count = 0 def increment(): global count count = count + 1 increment(); increment(); increment() print(count) # 3 # Way 2 — return the new value, don't mutate the global count = 0 def increment(c): return c + 1 count = increment(count)
Good practice: prefer returning a new value over using global. Functions that modify global state are harder to test and debug.

2.8 Passing Mutable vs Immutable Arguments

When you pass a variable to a function, Python sends the reference (the “address” of the object). If the object is immutable (int, float, str, tuple, bool), the function can’t change the original. If it is mutable (list, dict, set), the function can change the original.

2.8.1 Immutable argument — original is safe

def increase(x): x = x + 10 # rebinds the LOCAL x print("inside :", x) n = 5 increase(n) print("outside:", n) # 5 — unchanged
inside : 15 outside: 5

2.8.2 Mutable argument — original is changed!

def add_item(lst): lst.append(100) # modifies the SAME list object print("inside :", lst) nums = [1, 2, 3] add_item(nums) print("outside:", nums) # [1, 2, 3, 100] — caller’s list modified
inside : [1, 2, 3, 100] outside: [1, 2, 3, 100]
If you do not want the caller’s list to change, pass a copy: add_item(nums.copy()) or add_item(nums[:]).

2.9 CBSE-style Worked Programs

2.9.1 Function to check whether a number is even or odd

def is_even(n): return n % 2 == 0 print(is_even(4)) # True print(is_even(7)) # False

2.9.2 Function with default arguments — simple interest

def simple_interest(p, r=5, t=1): return (p * r * t) / 100 print(simple_interest(10000)) # r=5, t=1 → 500.0 print(simple_interest(10000, 8)) # r=8, t=1 → 800.0 print(simple_interest(10000, 8, 3)) # r=8, t=3 → 2400.0

2.9.3 Function returning multiple values — min and max of a list

def min_max(numbers): return min(numbers), max(numbers) marks = [78, 92, 65, 83, 71] lo, hi = min_max(marks) print(f"Lowest = {lo} Highest = {hi}")
Lowest = 65 Highest = 92

2.9.4 Factorial using a function

def factorial(n): f = 1 for i in range(2, n + 1): f *= i return f print(factorial(5)) # 120 print(factorial(0)) # 1

2.9.5 Count vowels in a string — using a function

def count_vowels(text): count = 0 for ch in text.lower(): if ch in "aeiou": count += 1 return count print(count_vowels("Computer Science")) # 6

2.9.6 Function to reverse a string

def reverse(s): return s[::-1] print(reverse("CBSE")) # ESBC

2.9.7 Using global — a web-visitor counter

visits = 0 def visit(): global visits visits += 1 for _ in range(5): visit() print("Total visits:", visits) # 5

2.9.8 Decomposition — a mini report-card

A bigger problem, solved by calling three small functions one after another.

def total(marks): return sum(marks) def percentage(marks): return total(marks) / len(marks) def grade(p): if p >= 90: return "A1" if p >= 80: return "A2" if p >= 70: return "B1" if p >= 60: return "B2" if p >= 50: return "C1" return "D" marks = [78, 85, 63, 92, 74] p = percentage(marks) print(f"Total : {total(marks)}") print(f"Percentage : {p:.2f}") print(f"Grade : {grade(p)}")
Total : 392 Percentage : 78.40 Grade : B1

2.10 Common Mistakes to Avoid

#MistakeFix
1Forgetting (): while callinggreet(), not just greet (that’s only the function object)
2Using print where you needed returnAsk: “does the caller need the value?”. If yes → return
3Reassigning a global without globalDeclare global var, or return a new value
4Mutable default like def f(a=[])Use a=None and create the list inside the body
5Non-default parameter after a defaultRe-order: defaults must come last
6Using a local variable outside its functionReturn it and store in a variable in the caller

Quick-revision summary

  • Three kinds of functions: built-in (len, print…), module (math.sqrt…), user-defined (written by you with def).
  • Function header: def name(params): — followed by an indented body and an optional return.
  • Parameter is the placeholder in def; argument is the real value in the call.
  • Argument kinds: positional, keyword, default. In a call, positional come first, then keyword; defaults must be the last parameters.
  • return sends a value back and stops the function. Multiple values are returned as a tuple.
  • A function without return returns None.
  • Scope — names are searched in LEGB order. To reassign a global from inside, use global.
  • Immutable arguments are safe; mutable arguments can be modified by the function.
🧠Practice Quiz — test yourself on this chapter