Answers for Python May 2023 QP
Problem Solving
with Python.
GE3151 · First Semester · Regulations 2021. Clear 2-mark definitions, structured 8/16-mark explanations, algorithms, flowchart, pseudocode and runnable Python programs — including both alternatives in the paper.
Part A — Short answers
Concise points you can reproduce in a two-mark answer.
Qualities of a good algorithm
2 marksA good algorithm should have these characteristics:
- Correctness: produces the expected result.
- Finiteness: terminates after a finite number of steps.
- Definiteness: every step is clear and unambiguous.
- Input and output: accepts zero or more inputs and produces at least one result where required.
- Effectiveness: steps are basic and executable.
- Efficiency: uses reasonable time and memory.
Strategies for developing an algorithm
2 marksCommon problem-solving strategies include:
- Top-down: split a large problem into smaller subproblems.
- Bottom-up: build a solution from smaller components.
- Divide and conquer: divide, solve subproblems, then combine.
- Greedy: choose the best local option at each step.
- Dynamic programming: store and reuse results of overlapping subproblems.
- Backtracking / brute force: explore possible choices or systematically test candidates.
In a short answer, state the strategies taught in your class notes if the lecturer uses a narrower list.
Rules for writing an identifier
2 marks- Must begin with a letter (
A–Z,a–z) or underscore (_). - After the first character, may contain letters, digits and underscores.
- Cannot contain spaces or punctuation such as
-,@or!. - Cannot be a Python keyword such as
if,fororclass. - Identifiers are case-sensitive:
totalandTotaldiffer.
Valid student_1, _count Invalid: 1student, student-name
Types of arguments in Python
2 marksThe common kinds are:
- Positional: matched by order, e.g.
add(2, 3). - Keyword: passed by parameter name, e.g.
add(a=2, b=3). - Default: parameter has a preset value if omitted.
- Variable-length:
*argsaccepts extra positional arguments and**kwargsaccepts extra keyword arguments.
Return value and composition
2 marksReturn value: the result a function sends back to its caller using return.
Function composition: combining function calls so that the output of one function becomes the input of another.
def double(x):
return 2 * x
def add_one(x):
return x + 1
result = add_one(double(3)) # 7The function double returns 6; then add_one receives that result and returns 7.
String immutability
2 marksStrings in Python are immutable, meaning their characters cannot be changed in place after the string is created. Operations that appear to modify a string create a new string.
s = "cat"
# s[0] = "b" # TypeError
s = "b" + s[1:] # creates "bat"Cloning in a list
2 marksCloning creates a separate list object containing the same elements as the original list. For a shallow copy, use slicing or copy().
a = [10, 20, 30]
b = a[:] # or: b = a.copy()
b[0] = 99
print(a) # [10, 20, 30]
print(b) # [99, 20, 30]A shallow copy does not recursively copy nested mutable objects.
Benefit of tuple assignment
2 marksTuple assignment (sequence unpacking) assigns multiple variables in one statement. It makes code concise and allows variables to be swapped without a temporary variable.
a, b = 5, 9
a, b = b, a
print(a, b) # 9 5How to delete a file in Python
2 marksUse os.remove() or Path.unlink(). Ensure the path is correct and handle possible file errors.
import os
os.remove("old_file.txt")Deleting a file is destructive. Check the path before running this code.
Command-line arguments
2 marksCommand-line arguments are values supplied after the script name when running a program. The sys.argv list in the sys module stores them as strings; sys.argv[0] is the script name.
import sys
print("Hello", sys.argv[1])Run with python hello.py Ravi; output: Hello Ravi.
Algorithms, recursion & languages
Both (a) and (b) alternatives are answered below.
Iteration and recursion with examples
8 marksIteration repeats a block using a loop such as for or while. Recursion solves a problem by having a function call itself on a smaller input. A recursive function must have a base case to stop the calls.
| Iteration | Recursion |
|---|---|
| Uses loops. | Uses repeated function calls. |
| Stops when the loop condition becomes false. | Stops when the base case is reached. |
| Usually uses constant call-stack space. | Uses call-stack space for each pending call. |
| Often efficient for straightforward repetition. | Can express naturally recursive problems clearly. |
Example: factorial where n! = n × (n−1) × … × 1 and 0! = 1.
def factorial_iterative(n):
if n < 0:
raise ValueError("n must be non-negative")
result = 1
for i in range(2, n + 1):
result *= i
return result
def factorial_recursive(n):
if n < 0:
raise ValueError("n must be non-negative")
if n == 0 or n == 1: # base case
return 1
return n * factorial_recursive(n - 1)
print(factorial_iterative(5)) # 120
print(factorial_recursive(5)) # 120Conclusion: both methods calculate the same result. Iteration avoids recursive call overhead; recursion can make a naturally recursive definition easier to understand.
Algorithm and flowchart for net salary
8 marksAssumption: the question gives no particular salary percentages. Read the earnings components and total deductions as inputs.
Algorithm
- Start.
- Read basic pay, allowances and deductions.
- Calculate
gross = basic + allowances. - Calculate
net = gross − deductions. - Display gross and net salary.
- Stop.
basic = float(input("Enter basic pay: "))
allowances = float(input("Enter total allowances: "))
deductions = float(input("Enter total deductions: "))
gross = basic + allowances
net = gross - deductions
print(f"Gross salary: {gross:.2f}")
print(f"Net salary: {net:.2f}")Machine, assembly and high-level languages
8 marks| Feature | Machine language | Assembly language | High-level language |
|---|---|---|---|
| Representation | Binary bits (0 and 1) | Mnemonics such as MOV | English-like statements, e.g. Python |
| Hardware dependence | Machine-specific | Machine-specific | Usually more portable |
| Translator | Executed by CPU | Assembler | Compiler or interpreter (implementation-dependent) |
| Ease of writing | Very difficult | More readable than machine code | Generally easiest to write and maintain |
| Control | Direct low-level control | Close hardware control | Higher abstraction from hardware |
Examples: machine code bytes; assembly instructions; Python, C, Java. High-level languages still need translation or a runtime before execution by the machine.
Pseudocode: maximum in a list & Towers of Hanoi
8 marks1. Find maximum in a non-empty list
ALGORITHM FindMaximum(A)
IF length(A) = 0 THEN
REPORT "List is empty" and STOP
max ← A[0]
FOR each item x in A from the second item
IF x > max THEN
max ← x
END IF
END FOR
OUTPUT max
END ALGORITHM2. Towers of Hanoi — move n disks from source to destination using an auxiliary peg; move only one disk at a time and never put a larger disk on a smaller one.
PROCEDURE Hanoi(n, source, auxiliary, destination)
IF n = 1 THEN
OUTPUT "Move disk 1 from", source, "to", destination
ELSE
Hanoi(n - 1, source, destination, auxiliary)
OUTPUT "Move disk", n, "from", source, "to", destination
Hanoi(n - 1, auxiliary, source, destination)
END IF
END PROCEDUREThe number of moves for n disks is 2ⁿ − 1.
Variables and operators
Naming rules, swapping, precedence and leap years.
Rules for naming variables, with examples
8 marks- A variable name starts with a letter or underscore, not a digit.
- It can contain letters, digits and underscores only.
- Spaces and symbols such as hyphens are not allowed.
- A Python keyword cannot be used as a variable name.
- Names are case-sensitive.
- Use meaningful names such as
total_marksrather than unclear names.
| Name | Validity | Reason |
|---|---|---|
student_name | Valid | Letters and underscore |
mark2 | Valid | Digit appears after first character |
_total | Valid | May begin with underscore |
2marks | Invalid | Begins with a digit |
total-marks | Invalid | Hyphen is an operator |
class | Invalid | Reserved keyword |
Python program to swap two variables
8 marksPython supports simultaneous assignment, so a temporary variable is not required.
a = input("Enter first value: ")
b = input("Enter second value: ")
print("Before swapping:", a, b)
a, b = b, a
print("After swapping:", a, b)Example: if inputs are 12 and 30, after swapping the values are 30 and 12. Inputs are strings here; use int(input(...)) for integer-only values.
Operator precedence and order
8 marksPrecedence determines which operator is evaluated first when an expression contains operators of different priorities. Parentheses can be used to make the intended order explicit.
| Higher → lower | Operators / examples |
|---|---|
| 1 | Parentheses/grouping: () |
| 2 | Exponentiation: ** |
| 3 | Unary plus/minus and bitwise NOT: +x, -x, ~x |
| 4 | Multiplication, division, floor division, remainder: * / // % |
| 5 | Addition and subtraction: + - |
| 6 | Shifts: << >> |
| 7–9 | Bitwise AND &, XOR ^, OR | |
| 10 | Comparisons, membership and identity: < <= == != in is |
| 11 | Logical NOT: not |
| 12 | Logical AND: and |
| 13 | Logical OR: or |
Example 1: 2 + 3 * 4 = 14, because multiplication comes before addition. Example 2: (2 + 3) * 4 = 20, because parentheses are evaluated first.
Associativity: operators of equal precedence generally group left to right, but exponentiation groups right to left: 2 ** 3 ** 2 = 2 ** (3 ** 2) = 512. Unary signs and exponentiation have a special relationship, so use parentheses when clarity matters.
Python program to test a leap year
8 marksA year is a leap year when it is divisible by 400, or divisible by 4 but not divisible by 100.
year = int(input("Enter a year: "))
if year % 400 == 0:
print(year, "is a leap year")
elif year % 100 == 0:
print(year, "is not a leap year")
elif year % 4 == 0:
print(year, "is a leap year")
else:
print(year, "is not a leap year")Test: 2000 is a leap year; 1900 is not; 2024 is a leap year; 2023 is not.
Strings, arrays & searching
String module explanation and two common programs.
Explain the Python string module
8 marksThe standard-library string module supplies useful string constants and a few helper functions. It is imported using import string.
| Member | Purpose |
|---|---|
string.ascii_lowercase | Lowercase English letters a-z |
string.ascii_uppercase | Uppercase English letters A-Z |
string.ascii_letters | Lowercase and uppercase ASCII letters |
string.digits | Decimal digits 0-9 |
string.hexdigits | Hexadecimal digit characters |
string.punctuation | ASCII punctuation characters |
string.whitespace | Whitespace characters recognised by the module |
string.capwords(text) | Splits words, capitalises them and joins them with spaces |
import string
print(string.ascii_lowercase)
print(string.digits)
print(string.punctuation)
print(string.capwords("problem solving with python"))
# Problem Solving With PythonNote: methods such as upper(), lower(), split() and replace() are methods of string objects, rather than constants in the string module.
Find sum and average of an array of numbers
8 marksThis solution uses a Python list to store the values; it calculates the total and then divides by the number of values.
n = int(input("How many numbers? "))
if n <= 0:
print("Enter a positive count")
else:
numbers = []
for i in range(n):
value = float(input(f"Enter number {i + 1}: "))
numbers.append(value)
total = sum(numbers)
average = total / len(numbers)
print("Numbers:", numbers)
print("Sum =", total)
print("Average =", average)Formula: Sum = x₁ + x₂ + … + xₙ; average = sum / n. Checking that n > 0 prevents division by zero.
Sequential (linear) search of a list
16 marksDefinition: Sequential search examines list elements one by one from the beginning. It stops when the key is found or when all elements have been checked. It works on unsorted as well as sorted lists.
Algorithm
- Read the list and search key.
- Set index
i = 0. - While
iis less than the list length, compare the element at indexiwith the key. - If equal, report the position and stop.
- Otherwise increment
iand continue. - If the end is reached, report that the key was not found.
def linear_search(items, key):
for index, value in enumerate(items):
if value == key:
return index # zero-based index
return -1
values = [12, 7, 25, 4, 18]
key = int(input("Enter the value to search: "))
position = linear_search(values, key)
if position != -1:
print("Found at position", position + 1)
else:
print("Value not found")Example: For [12, 7, 25, 4, 18], key 25 is found at position 3 (human counting starts at 1). If the key is absent, the function returns -1.
| Performance | Result |
|---|---|
| Best case | O(1) — key is first |
| Worst case | O(n) — key is last or absent |
| Extra space | O(1) for this iterative implementation |
Lists and electricity billing
Long-form list operations and a billing program based on the given table.
Lists, list operations and list slices
16 marksList: a list is an ordered, mutable sequence that can store elements of different data types. It is written using square brackets, for example marks = [78, 85, 92]. List indexes start at 0, and negative indexes count from the end.
Common list operations
| Operation | Example | Meaning |
|---|---|---|
| Access / update | a[0], a[1] = 8 | Read or replace an element |
| Append | a.append(4) | Add one item at the end |
| Extend | a.extend([5, 6]) | Add items from an iterable |
| Insert | a.insert(1, 9) | Insert at a specific index |
| Remove | a.remove(9) | Remove first matching value |
| Pop | a.pop() | Remove and return an item; default is last |
| Delete | del a[0] | Delete an item or slice |
| Sort / reverse | a.sort(), a.reverse() | Sort in place / reverse in place |
| Search helpers | a.index(4), a.count(4) | Find first index / count matches |
| Combine / repeat | a + b, a * 2 | Concatenate / repeat a list |
| Length / membership | len(a), 4 in a | Get item count / test presence |
List slicing: list[start:stop:step] extracts a subsequence. The start index is included, but the stop index is excluded. Omitting start or stop uses a default boundary.
a = [10, 20, 30, 40, 50, 60]
print(a[0]) # 10
print(a[-1]) # 60
print(a[1:4]) # [20, 30, 40]
print(a[:3]) # [10, 20, 30]
print(a[3:]) # [40, 50, 60]
print(a[::2]) # [10, 30, 50]
print(a[::-1]) # [60, 50, 40, 30, 20, 10]
copy_of_a = a[:] # shallow cloneImportant: lists are mutable, so operations such as item assignment, append() and remove() change the list itself. A slice generally creates a new list (a shallow copy), while a slice assignment can modify the original list.
Electricity bill based on units and consumer type
16 marksThe program reads units consumed and whether the connection is domestic or commercial, then selects the corresponding price from the printed table.
| Units as printed on paper | Domestic price | Commercial price |
|---|---|---|
| Up to 200 units | 200 (base price) | 500 |
| Units > 200 and < 500 | 1100 | 1700 |
| Units > 500 and < 1000 | 4500 | 7000 |
units = int(input("Enter units consumed: "))
kind = input("Connection type (domestic/commercial): ").strip().lower()
if units < 0:
print("Units cannot be negative")
elif kind not in ("domestic", "commercial"):
print("Enter domestic or commercial")
elif units <= 200:
bill = 200 if kind == "domestic" else 500
print(f"Electricity bill: {bill}")
elif 200 < units < 500:
bill = 1100 if kind == "domestic" else 1700
print(f"Electricity bill: {bill}")
elif 500 < units < 1000:
bill = 4500 if kind == "domestic" else 7000
print(f"Electricity bill: {bill}")
else:
print("Tariff not specified for this unit count in the question paper")Note: These are flat prices for the unit bands shown in the question, not per-unit multiplication. If your lecturer expects 500 to be included in the middle band or 1,000 in the highest band, confirm that intended boundary rule before changing the conditions.
File handling and stack
File copy in chunks, text-file counting, and a modular stack implementation.
Copy a file 50 characters at a time
8 marksRead at most 50 characters in each iteration and write that chunk to the destination until no characters remain.
def copy_file(source_name, destination_name):
with open(source_name, "r", encoding="utf-8") as source:
with open(destination_name, "w", encoding="utf-8") as destination:
while True:
chunk = source.read(50)
if chunk == "":
break
destination.write(chunk)
copy_file("input.txt", "copy.txt")
print("File copied successfully")Explanation: read(50) returns up to 50 characters. An empty string indicates end-of-file. The with statement closes both files automatically.
This character-based version is suitable for text files. For arbitrary binary files, use binary modes (rb/wb) and read chunks as bytes.
Count lines, words and characters in a text file
8 marksIn this answer, characters include spaces and newline characters because the entire text is read as-is.
with open("input.txt", "r", encoding="utf-8") as file:
text = file.read()
characters = len(text)
words = len(text.split())
lines = len(text.splitlines())
print("Lines:", lines)
print("Words:", words)
print("Characters:", characters)Explanation: split() separates text on runs of whitespace, while splitlines() separates line breaks. For a completely empty file, both counts are zero.
If the examiner defines a blank file or a trailing newline as a line differently, state the counting convention you use.
Implement stack operations using modules
16 marksA stack is a Last-In, First-Out (LIFO) data structure. The main operations are push (insert at top), pop (remove the top item), peek (view the top item), and display.
Save the first program as stack_module.py and the second as main.py in the same folder.
_stack = []
def push(item):
_stack.append(item)
print(item, "pushed")
def pop():
if not _stack:
print("Stack underflow: stack is empty")
return None
return _stack.pop()
def peek():
if not _stack:
return None
return _stack[-1]
def display():
if not _stack:
print("Stack is empty")
else:
print("Bottom → top:", _stack)
def is_empty():
return len(_stack) == 0import stack_module as stack
while True:
print("\n1.Push 2.Pop 3.Peek 4.Display 5.Exit")
choice = input("Enter choice: ").strip()
if choice == "1":
item = input("Enter item: ")
stack.push(item)
elif choice == "2":
item = stack.pop()
if item is not None:
print("Popped:", item)
elif choice == "3":
item = stack.peek()
if item is None:
print("Stack is empty")
else:
print("Top item:", item)
elif choice == "4":
stack.display()
elif choice == "5":
print("Program ended")
break
else:
print("Invalid choice")Working: the main program imports the module and calls its functions. The stack module stores stack data and implements each operation. Popping an empty stack is called stack underflow, which is handled here with a message.
Quick revision quiz
Five fast checks to see what stuck. Try before revealing your score.
1. Which structure follows Last-In, First-Out?
2. What is the output of 2 + 3 * 4?
3. Which operation creates a shallow list copy?
4. Which is the correct leap-year rule?
5. What does an empty string returned by file.read(50) indicate?
Exam-writing tip
For an 8- or 16-mark programming answer, aim to write the definition or logic, a short algorithm / explanation, the complete program, and one sample result where appropriate. Use indentation consistently and mention assumptions if the question leaves a rule unspecified.
Prepared from the uploaded GE3151 question paper (Question Paper Code 30198, April/May 2023). Some wording, notably the strategy list and the electricity-tariff boundaries, may depend on your prescribed class notes.
Comments
Post a Comment