📌 Snapshot
- Master def, parameters, return, scope and the math, random and statistics modules for CUET Python questions.
- Why functions exist, and how arguments, defaults and return values travel between the caller and the function.
- Local versus global variables traced step by step, plus tables of the built in and module functions NTA picks from.
- Traps to avoid: calling before defining, a function that returns None, and random.randint versus randrange.
📖 Detailed Notes
Written and reviewed by Rohit Singh, Computer Science & Commerce faculty at UniDrill (MCA, Osmania University · 6 years teaching). Based on NCERT Computer Science Class XI, Chapter 7.
Why write the same code only once?
A company makes tents shaped like a cylinder with a cone on top. To fix the price it must find the canvas area of the cylinder, the canvas area of the cone, the cost, and the final amount after 18% tax. Written as one long program, the calculation works, but it is bulky, hard to read and impossible to reuse. Now suppose the company designs a tent with a rectangular base and the same cone on top. With a long program you copy and paste. With functions you simply call the cone calculation again. Splitting a program into separate, named blocks, each with one job, is called modular programming, and the function is Python's main tool for it.
What is a function?
A function is a named group of instructions that does a specific task when it is called. You write it once and call it as many times as you like, from anywhere in the program or from inside another function.
| Advantage | Why it helps |
|---|---|
| Readability | A long program becomes a list of well named steps |
| Shorter code | The same instructions are not repeated, which also makes debugging easier |
| Reusability | A function can be called from another function, or even another program |
| Teamwork | Different people can write different functions at the same time |
Python gives you three kinds of function, and the chapter follows this order.
| Kind | Who writes it | Examples |
|---|---|---|
| Built in function | Python itself; always available | print(), input(), len(), max() |
| Module function | The standard library; available after an import |
math.sqrt(), random.randint() |
| User defined function | You | calcFact(), post_tax_price() |
Defining and calling a user defined function
A definition starts with the keyword def, then the function name, a pair of brackets holding the optional parameters, and a colon. The body is indented underneath.
| Code |
|---|
def addnum(): |
fnum = int(input("Enter first number: ")) |
snum = int(input("Enter second number: ")) |
print("The sum is", fnum + snum) |
addnum() |
The last line is the call: the function name followed by brackets. Four rules from the syntax are exam favourites. The header ends with a colon. The function name follows the same rules as any identifier. Parameters are optional, and a function may or may not return a value. Statements that are not indented under the header are not part of the function.
Flow of execution: what runs when
When Python meets a def, it only remembers the function. The body does not run. The body runs when the function is called. At a call, control jumps into the function, runs its statements, and returns to the point of the call. This is the flow of execution, and it is why you must read a program in the order of execution, not simply from top to bottom.
Worked example: order of execution.
| Code |
|---|
def show(): |
print("A") |
print("B") |
show() |
print("C") |
| Step | Statement reached | What happens |
|---|---|---|
| 1 | def show(): |
Python stores the function; nothing printed |
| 2 | show() |
Call: control jumps into the body |
| 3 | print("A") |
Prints A |
| 4 | print("B") |
Prints B; the body ends and control returns |
| 5 | print("C") |
Prints C |
| Output |
|---|
A |
B |
C |
A function must be defined before it is called. If the call line comes first, the interpreter has not yet seen the def, and the program stops with NameError: name 'helloPython' is not defined. The fix is simply to move the definition above the call.
Pause and predict: a program contains only the lines def hello(): and, indented beneath it, print("Hi"). Nothing else. What is printed when you run it?
Check your answer: nothing at all. The definition only stores the function. Without a call such as hello(), the body never runs.
Parameters, arguments and default values
A parameter is the name in the function header that receives a value. An argument is the actual value passed in the call. In sumSquares(num), num is the argument and the header def sumSquares(n): holds the parameter n. Arguments and parameters are matched in order, and an argument can be an expression, which Python evaluates before the call.
| Term | Where it appears | Role |
|---|---|---|
| Parameter | In the function definition (header) | Local name that receives the value |
| Argument | In the function call | The actual value (or expression) sent |
You can also give a parameter a default value, which is used when the call leaves that argument out. The rule: default parameters must be the trailing ones. If a parameter has a default, every parameter to its right must also have one.
| Header | Valid? | Why |
|---|---|---|
def f(num, deno=1) |
Valid | The only default is last |
def f(num=2, deno=1) |
Valid | Both have defaults |
def calcInterest(rate, principal=1000, time=5) |
Valid | Defaults are trailing |
def calcInterest(principal=1000, rate, time=5) |
Invalid | rate has no default but sits to the right of one that does |
Worked example: default values. What do the three calls return?
| Code |
|---|
def interest(p, r=5, t=2): |
return p * r * t / 100 |
print(interest(1000)) |
print(interest(1000, 10)) |
print(interest(1000, 10, 3)) |
| Call | Values bound to p, r, t | Calculation | Printed |
|---|---|---|---|
interest(1000) |
1000, 5 (default), 2 (default) | 1000 x 5 x 2 / 100 | 100.0 |
interest(1000, 10) |
1000, 10, 2 (default) | 1000 x 10 x 2 / 100 | 200.0 |
interest(1000, 10, 3) |
1000, 10, 3 | 1000 x 10 x 3 / 100 | 300.0 |
The result prints as 100.0 and not 100 because / always gives a float.
Returning values
A function does its work in one of two ways: it displays a result with print(), or it returns it with return. The return statement does two things: it sends control back to the caller and it hands over a value (or None if you give nothing). A function without a return statement is called a void function, and it returns None.
Because a function may or may not take arguments and may or may not return a value, there are four combinations.
| Type | Takes arguments? | Returns a value? | Example idea |
|---|---|---|---|
| 1 | No | No | A function that reads two numbers and prints their sum |
| 2 | No | Yes | A function that reads a number and returns it |
| 3 | Yes | No | sumSquares(n) that prints the sum of the first n numbers |
| 4 | Yes | Yes | calcpow(base, exp) that returns base raised to exp |
Pause and predict: def f(): print("hi"). Then you run r = f() followed by print(r). What appears on the screen?
Check your answer: hi and then None. The call prints hi inside the function, but since there is no return, the value stored in r is None.
Returning more than one value. Python returns several values together as a tuple, which you can unpack in the same order.
Worked example: area and perimeter of a rectangle.
| Code |
|---|
def rect(l, b): |
return l * b, 2 * (l + b) |
a, p = rect(4, 3) |
print(a, p) |
print(rect(4, 3)) |
| Step | What happens | Result |
|---|---|---|
| 1 | rect(4, 3) runs with l = 4, b = 3 |
|
| 2 | The expression l * b, 2 * (l + b) is evaluated |
12 and 14 |
| 3 | The two values are packed into a tuple and returned | (12, 14) |
| 4 | a, p = ... unpacks the tuple in order |
a is 12, p is 14 |
| Output |
|---|
12 14 |
(12, 14) |
Does changing the parameter change the caller's variable? For numbers and strings, no. Reassigning a parameter makes it point to a new value, and the caller's variable is untouched.
| Code |
|---|
def incr(num): |
num = num + 5 |
return num |
n = 8 |
incr(n) |
print(n) |
This prints 8. At the call, n and num refer to the same value 8 (and id() shows the same number for both). But num = num + 5 creates a new value 13 and makes only num refer to it, so id(num) changes while n still refers to 8. Chapter 9 shows that a list behaves differently, because it can be changed in place.
Scope of a variable
The part of a program where a variable can be used is its scope. There are two kinds.
| Feature | Local variable | Global variable |
|---|---|---|
| Created | Inside a function or block | Outside every function |
| Can be used | Only inside that function | Anywhere defined after it, including inside functions |
| Lifetime | Exists only while the function runs | Exists until the program ends |
| Outside access | NameError |
Allowed |
If a function creates a variable with the same name as a global one, the function gets its own local variable, which hides the global one. The global stays unchanged. To change the global itself from inside a function, declare it with the keyword global.
Worked example: local versus global.
| Code |
|---|
x = 10 |
def f(): |
x = 5 |
print(x) |
f() |
print(x) |
| Step | What happens | Value of x seen |
|---|---|---|
| 1 | Global x is created |
10 |
| 2 | f() runs; x = 5 makes a new local x |
5 (local) |
| 3 | print(x) inside f |
prints 5 |
| 4 | f ends, its local x disappears |
|
| 5 | print(x) outside |
prints 10 |
The common wrong answer is 5 and 5, which assumes the function changed the global. Now add one line, global x, as the first line inside f. With it, x = 5 rebinds the global variable, so the output becomes 5 and then 5.
Beyond the textbook. For the exam: a variable assigned inside a function is local, and a global must be declared with global to be changed. In reality: Python decides whether a name is local by looking at the whole function body, not line by line. So in def k(): y = y + 1, with y global, Python treats y as local because it is assigned in the body, and then fails on the right side with UnboundLocalError because no local y exists yet. Reading a global without assigning to it works without any global keyword.
Pause and predict: a global count = 0. A function inc() contains only count = count + 1. You call inc(). What happens?
Check your answer: an error. The assignment makes count local to inc(), so the right side tries to read a local count that has no value yet. Adding global count at the top of the function fixes it.
Built in functions
Built in functions are ready made. Their code is already inside the interpreter, so no import is needed. You have already used input(), int() and print(). A quick way to understand any function is to ask: does it accept a value, and does it return one? input("Enter name: ") accepts the prompt and returns the typed text, while print() accepts values and returns nothing useful.
| Function | Returns | Example | Result |
|---|---|---|---|
abs(x) |
Absolute value | abs(-5.7) |
5.7 |
divmod(x, y) |
Tuple (quotient, remainder) | divmod(7, 2) |
(3, 1) |
max(seq) or max(x, y, z) |
Largest value; strings compare by ASCII value | max("Sincerity") |
'y' |
min(seq) or min(x, y, z) |
Smallest value; uppercase letters come before lowercase | min("Sincerity") |
'S' |
pow(x, y) |
x raised to y | pow(5, 2) |
25 |
pow(x, y, z) |
(x raised to y) mod z | pow(5, 2, 4) |
1 |
sum(seq) |
Sum of the elements | sum([2, 4, 7, 3]) |
16 |
sum(seq, n) |
Sum plus the optional start value n | sum([2, 4, 7, 3], 3) |
19 |
len(x) |
Number of elements | len("Patience") |
8 |
For negative numbers divmod uses floor division, so divmod(-7, 2) is (-4, 1), because $-4 \times 2 + 1 = -7$.
Modules and the import statement
A module is a Python file (.py) that holds a collection of function definitions. A function is a grouping of instructions, and a module is a grouping of functions. To use one, import it, then call its functions as modulename.functionname(). The from form brings in only the functions you name, and you then call them without the module name.
| Form | Syntax | How you call it |
|---|---|---|
| Whole module | import math |
math.sqrt(144) |
| Selected functions | from math import ceil, sqrt |
sqrt(144) |
A module is loaded only once, however many times you import it. Module names are all lowercase, because Python is case sensitive. Importing only what you need keeps the program light.
The math module returns floats for most functions.
| Function | Meaning | Example | Result |
|---|---|---|---|
math.ceil(x) |
Smallest integer not below x | math.ceil(-9.7) |
-9 |
math.floor(x) |
Largest integer not above x | math.floor(-4.5) |
-5 |
math.fabs(x) |
Absolute value as a float | math.fabs(-4) |
4.0 |
math.factorial(x) |
x! for a non negative integer | math.factorial(5) |
120 |
math.gcd(x, y) |
Greatest common divisor | math.gcd(10, 2) |
2 |
math.pow(x, y) |
x to the power y, always a float | math.pow(3, 2) |
9.0 |
math.sqrt(x) |
Square root | math.sqrt(144) |
12.0 |
math.fmod(x, y) |
Remainder with the sign of x | math.fmod(4, 4.9) |
4.0 |
math.sin(x) |
Sine of x, x in radians | math.sin(0) |
0.0 |
Ceiling and floor are opposites on the number line: the ceiling of 9.7 is 10 and the floor is 9, but for negative numbers the ceiling of -9.7 is -9 (towards zero) and the floor of -4.5 is -5 (away from zero). Do not confuse either with simply chopping off the decimal part, which is what math.trunc() does.
The random module generates random numbers.
| Function | Returns | Range |
|---|---|---|
random.random() |
A random float | From 0.0 up to, but not including, 1.0 |
random.randint(x, y) |
A random integer | x to y, both included |
random.randrange(y) |
A random integer | 0 up to y, y excluded |
random.randrange(x, y) |
A random integer | x up to y, y excluded |
The statistics module works on a numeric sequence.
| Function | Returns | Example on [11, 24, 32, 45, 51] |
|---|---|---|
statistics.mean(x) |
Arithmetic mean | 32.6 |
statistics.median(x) |
Middle value | 32 |
statistics.mode(x) |
Most repeated value | statistics.mode([11, 24, 11, 45, 11]) gives 11 |
Composition. When the output of one function becomes the input of another, you have composition. The inner call runs first. For example, sqrt(ceil(624.7)) first computes ceil(624.7), which is 625, and then sqrt(625), which is 25.0. In the same way, trunc(625.7) cuts the decimal part and gives 625, so sqrt(trunc(625.7)) is also 25.0.
Beyond the textbook. For the exam: pow(5, 2) gives 25 and math.pow(5, 2) gives 25.0, so the built in pow keeps integers as integers while math.pow always returns a float. In reality: the built in pow also accepts a third argument for modular arithmetic, pow(5, 2, 4), which is 25 mod 4, or 1. This is used widely in cryptography because it stays fast even for huge numbers.
Beyond the textbook. For the exam: the numbers from random are random. In reality: they are pseudo random: a formula produces them from a starting value, called the seed. If you fix the seed with random.seed(1), the same program prints the same "random" numbers every run, which is how programmers make a test repeatable.
Your own module. Save functions in a file such as basic_math.py, with a triple quoted docstring at the top describing the module. After import basic_math, the docstring is available as basic_math.__doc__ and the functions as basic_math.addnum(2, 5).
Exam traps
| The trap | Why it's tempting | The truth |
|---|---|---|
A function runs when its def is read |
The body is right there | def only stores the function; the body runs on a call |
| Calling above the definition is fine | Other languages declare earlier | The call must come after the def, or you get NameError |
| Parameter and argument are the same | Both mean "input" | Parameter is in the header; argument is in the call |
def f(a=1, b) is valid |
Defaults feel optional | Defaults must be trailing |
A function without return returns nothing |
No value is shown | It returns None |
| A function changes the global just by assigning | Same name, same variable | Assignment creates a local; use global |
randint(1, 5) can never return 5 |
Stop values are excluded in range |
randint includes both ends; randrange(1, 5) excludes 5 |
math.ceil(-9.7) is -10 |
Ceiling "rounds up in size" | Ceiling goes towards positive infinity: -9 |
60-second revision
| Topic | Lock this in |
|---|---|
| Function | Named block, runs only when called; reduces length, increases reuse |
| Header | def name(params): ends with a colon; body indented |
| Order | Definition before call, otherwise NameError |
| Parameter / argument | Header name / actual value, matched in order |
| Default values | Must be trailing parameters |
| return | Sends back control and a value; none means None; many values come as a tuple |
| Scope | Local inside the function, global outside; global to change a global |
| Built in | abs, divmod, max, min, pow, sum, len |
| Modules | import m then m.f(); from m import f then f(); loaded once |
| math | ceil, floor, fabs, factorial, fmod, gcd, pow, sqrt, sin |
| random | random() in 0.0 to 1.0; randint(x, y) includes y; randrange excludes the stop |
| statistics | mean, median, mode |
Where this chapter connects
- Previous: Flow of Control gives the decisions and loops that fill the body of nearly every function here.
- Next: Strings uses many functions and methods, and its programs are written as user defined functions.
- Later in this unit: Lists shows how a list behaves differently when passed to a function, and Tuples and Dictionaries explains the tuple that carries multiple return values.
🎯 Practice MCQs
First 3 questions free · create a free account to unlock the rest — answers & explanations included, no payment needed
Q1. Which of the following function headers is valid in Python?
▸ Show answer & explanation
Answer: B
Parameters with default values must be the trailing ones. In option B the only default is the last parameter. In options A, C and D a parameter without a default appears to the right of one that has a default.
Q2. Consider: (1) def f(x): (2) x = x + 5 (3) return x (4) n = 8 (5) f(n) (6) print(n). Statements (2) and (3) are the body of f. What is printed?
▸ Show answer & explanation
Answer: B
The parameter x is rebound to a new value 13, but the caller's variable n still refers to 8. The returned value 13 is discarded because it is not stored or printed. So n stays 8.
Q3. Assertion (A): Calling a function before its def statement appears in the program raises a NameError. Reason (R): The function name is created only when the interpreter executes the def statement.
▸ Show answer & explanation
Answer: A
Python reads the program from top to bottom, and the name exists only after the def has run. A call placed earlier finds no such name, so a NameError is raised. R therefore explains A.
🔒 12 more practice MCQs
Create a free account to unlock every MCQ in this chapter — answers and explanations included. No payment needed.
Already registered? Just log in and they'll all appear here.
Q4. Match List I with List II. List I: (i) divmod(7, 2) (ii) pow(5, 2, 4) (iii) math.ceil(-9.7) (iv) max("Sincerity"). List II: (p) 1 (q) 'y' (r) (3, 1) (s) -9.
▸ Show answer & explanation
Answer: A
divmod(7, 2) returns the tuple (3, 1). pow(5, 2, 4) is 25 mod 4, which is 1. The ceiling of -9.7 is -9. For a string, max compares ASCII values, so the largest character in Sincerity is y. Options B, C and D each mismatch at least one pair.
Q5. Consider: (1) x = 10 (2) def f(): (3) x = 5 (4) print(x) (5) f() (6) print(x). Statements (3) and (4) are the body of f. What is printed, line by line?
▸ Show answer & explanation
Answer: C
Assigning x inside f creates a local variable that hides the global one. So f prints its local value 5, and the global x remains 10 for the last statement. Option A would need a global x declaration inside f.
Q6. Consider: (1) x = 10 (2) def f(): (3) global x (4) x = x + 1 (5) f() (6) f() (7) print(x). Statements (3) and (4) are the body of f. What is printed?
▸ Show answer & explanation
Answer: C
The global declaration makes x inside f refer to the global variable, so each call adds 1 to it. After two calls, x is 12. Without the declaration, option D would be correct.
Q7. Consider: (1) def f(): (2) print('hi') (3) r = f() (4) print(r). Statement (2) is the body of f. What is the output?
▸ Show answer & explanation
Answer: B
The call f() prints hi. Since f has no return statement it returns None, which is stored in r and printed by the last statement. Option A forgets that print(r) still runs.
Q8. A function ends with the statement: return a, b. What is the data type of the value that the caller receives?
▸ Show answer & explanation
Answer: C
Python packs multiple returned values into a tuple. They can be unpacked into separate variables in the same order. Options A and B would need square brackets or curly brackets, and the values are not joined into a string.
Q9. What is the value of math.sqrt(math.ceil(624.7)), after import math?
▸ Show answer & explanation
Answer: B
The inner call is evaluated first: math.ceil(624.7) is 625. Then math.sqrt(625) is 25.0, because sqrt always returns a float. Option A is wrong for that reason.
Q10. Which of the following calls can never return the value 7?
▸ Show answer & explanation
Answer: B
randint includes both end points, and randrange excludes the stop value. So randrange(3, 7) can give 3 to 6 only. The other three calls can return 7.
Q11. Which of the following statements are correct? (i) A module is a Python file that contains function definitions. (ii) After from math import sqrt, the function is called as sqrt(16) without the module name. (iii) A module imported more than once is loaded only once. (iv) Arguments are written in the function header and parameters in the call.
▸ Show answer & explanation
Answer: B
Statements (i), (ii) and (iii) are true. Statement (iv) is reversed: parameters are written in the header and arguments in the call. So only option B is correct.
Q12. What does statistics.mean([11, 24, 32, 45, 51]) return?
▸ Show answer & explanation
Answer: B
The sum is 163 and there are 5 values, so the mean is 163 divided by 5, which is 32.6. The value 32 is the median and 163 is only the sum.
Q13. Consider: (1) def show(): (2) print('A') (3) print('B') (4) show() (5) print('C'). Statements (2) and (3) are the body of show. In what order are the letters printed?
▸ Show answer & explanation
Answer: B
The def only stores the function. The call in statement (4) runs the body, printing A and B, and then control returns to print C. Option A reads the program strictly from top to bottom without following the call.
Q14. Consider: (1) def fn(a, b=2, c=3): (2) return a + b + c (3) print(fn(1, 1)). Statement (2) is the body of fn. What is printed?
▸ Show answer & explanation
Answer: B
The arguments are matched in order, so a is 1 and b is 1. The missing argument c takes its default value 3. The sum is 1 + 1 + 3, which is 5. Option C would be the result of fn(1).
Q15. Consider: (1) def sq(n): (2) return n multiplied by n (3) print(sq(sq(2) + 1)). Statement (2) is the body of sq. What is printed?
▸ Show answer & explanation
Answer: B
The innermost call sq(2) is 4. Adding 1 gives 5, and sq(5) is 25. Option A is sq(sq(2)) and option C is sq(2 + 1), which skip a step of the composition.
📊 Previous-Year Questions
Practise with real CUET Computer Science previous-year papers — every question solved, with the correct answer and a step-by-step explanation.
View solved CUET PYQ papers →Ready to drill Computer Science?
Unlock all MCQs, chapter tests, mocks & PYQs for ₹199/year.
Get UniDrill Pro