OOP in Python — NAUB Exam Revision Handout
NIGERIAN ARMY UNIVERSITY BIU
(NAUB)
Faculty of Computing
OBJECT ORIENTED PROGRAMMING IN PYTHON
Exam Revision Handout — Theory Q&A
101 Exam-Style Questions & Model Answers
Covering: OOP Principles · Data Structures · Classes & Objects · Inheritance & Polymorphism
Design Patterns · Advanced Features · Strings · Exceptions · Object Serialization
Prepared for: SEN/25U/5482 — Lawal Ibrahim
Software Engineering — Faculty of Computing
Note: This handout covers THEORY ONLY. Practice writing/tracing code separately using your lecture examples.
Page 1 of 12
OOP in Python — NAUB Exam Revision Handout
SECTION 1: INTRODUCTION TO OBJECT ORIENTED PROGRAMMING
Q1. What is Object Oriented Programming (OOP)?
Answer: OOP means programming that is directed towards objects. It is a technique used for modelling complex
systems by describing a collection of interacting objects through their data (attributes) and behavior (methods).
Python's OOP approach focuses on using objects and classes to design and build applications.
Q2. What are the major pillars (principles) of Object Oriented Programming?
Answer: The four major pillars of OOP are: Inheritance, Polymorphism, Abstraction, and Encapsulation. A language
must support classes and objects, plus these four principles, to be considered truly object-oriented.
Q3. What is Object Oriented Analysis (OOA)?
Answer: Object Oriented Analysis is the process of examining a problem, system, or task and identifying the objects
and the interactions that exist between them.
Q4. Why should we choose Object Oriented Programming?
Answer: OOP offers: a clear program structure that maps easily to real-world problems; easy maintenance and
modification of code; enhanced modularity since objects exist independently and new features can be added without
disturbing existing ones; a good framework for reusable code libraries; and code reusability.
Q5. Differentiate between Procedural Oriented Programming (POP) and Object Oriented
Programming (OOP).
Answer: POP is derived from structured programming and is based on functions/procedures/routines; data can be
freely accessed and changed. OOP decomposes a problem into objects and builds data and functions around those
objects. OOP emphasizes data more than procedures, and in OOP the data is hidden and cannot be accessed directly
by outside code (unlike in POP).
Q6. Explain Encapsulation as a principle of OOP.
Answer: Encapsulation hides unnecessary internal details of an object and exposes only what is needed, making a
program's structure easier to manage. Each object's implementation and state are hidden behind well-defined
boundaries, giving a clean, simple interface. This is commonly done by making data private.
Q7. Explain Inheritance as a principle of OOP.
Answer: Inheritance (also called generalization) allows a hierarchical relationship to be captured between classes and
objects — for example, 'fruit' is a generalization of 'orange'. It lets one class acquire the properties and behaviors of
another, which is very useful for code reuse.
Q8. Explain Abstraction as a principle of OOP.
Answer: Abstraction hides implementation details and exposes only the essential features of an object. For example,
a person pressing a scooter horn knows sound will be produced but does not need to know how the sound is
generated internally.
Q9. Explain Polymorphism as a principle of OOP.
Answer: Polymorphism means 'many forms' — the same action or thing can exist in different forms. A common
example is constructor overloading in classes, where the same method name behaves differently depending on the
object calling it.
Q10. What is a Module in Python and how does it relate to a dictionary?
Answer: A Python module is a package used to encapsulate reusable code. Modules reside in a folder (often with an
__init__.py file), contain functions and classes, and are imported using the 'import' keyword. A module behaves like
a dictionary: you retrieve items from it by name, except a dictionary uses [key] syntax with string keys, while a
module uses .key (dot) syntax with identifier names.
Q11. How is a Class similar to a Module?
Answer: A module is a specialized dictionary that stores Python code accessible with the dot (.) operator. A class
does the same thing but groups both functions and data inside a container, also accessed using the dot operator.
Classes are generally preferred over modules because they can be reused multiple times (instantiated repeatedly),
whereas a module exists only once in a program.
Page 2 of 12
OOP in Python — NAUB Exam Revision Handout
Q12. How are Objects related to 'mini-imports'?
Answer: A class behaves like a mini-module, and creating an object from a class (instantiation) is similar to
importing a module. When you instantiate a class, you get an object that can access the class's functions (methods)
and variables (attributes) using the dot operator.
SECTION 2: PYTHON DATA STRUCTURES
Q13. What is a List in Python?
Answer: A List is the most versatile Python data structure. It is a container holding comma-separated values (items)
between square brackets [ ]. Lists are useful for grouping related values together so the same operations can be
performed on multiple values at once. List indices start from 0, and lists are mutable (their contents can be changed).
Q14. How are items accessed in a Python List?
Answer: Each item in a list has an index (position), starting from 0 for the first item. Items are accessed using square
brackets with the index number, e.g., list[0] for the first item. Negative indices count from the end, so list[-1]
accesses the last item.
Q15. What is an Empty Object in Python and why is it used?
Answer: An Empty Object is the simplest built-in Python type, created using object() or an empty class (using 'pass').
Its main purpose is to act as a placeholder to block something temporarily before extending it later with real
attributes and behavior. Direct instances of the built-in object type cannot have arbitrary attributes added to them, but
an empty user-defined class can.
Q16. What is a Tuple and how does it differ from a List?
Answer: A Tuple is similar to a list but is immutable, meaning elements cannot be added, removed, or replaced after
creation. Because of this immutability, tuples can be used as dictionary keys or wherever a hash value is required.
Tuples are used to store data (not behavior) and are enclosed in parentheses ( ), though the parentheses are optional.
Q17. List the properties of Tuples that result from their immutability.
Answer: Because tuples are immutable: you cannot add elements to a tuple; you cannot append or extend it; you
cannot remove elements from it; tuples have no remove() or pop() method. Only count() and index() methods are
available on tuples.
Q18. What is a Dictionary in Python?
Answer: A Dictionary is one of Python's built-in data types that defines a one-to-one relationship between keys and
values. Each element is a key-value pair enclosed in curly braces { }. You can retrieve a value using its key, but you
cannot look up a key using its value.
Q19. State the key rules about modifying a Dictionary.
Answer: You cannot have duplicate keys in a dictionary — assigning a new value to an existing key overwrites
(deletes) the old value. New key-value pairs can be added at any time. Dictionaries have no concept of order among
their elements; they are simple unordered collections.
Q20. How do you delete items from a Dictionary?
Answer: The 'del' keyword deletes an individual item from a dictionary by specifying its key (e.g., del
my_dict['key']). The clear() method deletes all items from the dictionary at once, leaving it empty.
Q21. What is a Set in Python?
Answer: A Set is an unordered collection with no duplicate elements. Although individual items in a set are
immutable, the set itself is mutable — elements can be added or removed. Sets support mathematical operations like
union and intersection. Python implements sets using a hash table, which allows very fast checking of whether an
element exists in the set.
Q22. How is a Set created in Python?
Answer: A set is created by placing items inside curly braces { }, separated by commas, or by using the built-in set()
function.
Page 3 of 12
OOP in Python — NAUB Exam Revision Handout
Q23. Name common Set operations and what they do.
Answer: add(x) adds an element to the set. union(s) returns a set combining all elements of both sets. intersection(s)
returns only the elements common to both sets. difference(s) returns elements in the first set but not in the second.
clear() empties the entire set. Sets also support operators: | for union, & for intersection, - for difference, and
isdisjoint() to check if two sets share no common elements.
SECTION 3: CLASSES, OBJECTS AND BUILDING BLOCKS
Q24. What is a Class?
Answer: A Class is a factory or blueprint for creating instances (objects). It describes how to build the instances —
what attributes and methods they will have. Every instance created from a class is expected to share the same set of
attributes defined by that class.
Q25. What is an Object (Instance)?
Answer: An Object (or instance) is a specific realization of a class, created from the class blueprint, that carries out
the functionality defined in that class. Multiple objects can be created from a single class, and each exists
independently in memory.
Q26. Explain how a Class bundles 'behavior' and 'state' together.
Answer: A class packages together behavior and state. 'Behavior' refers to functions/methods — pieces of code that
do something. 'State' refers to variables — places to store values within the class. Bundling behavior and state
together is one of the core ideas of a class.
Q27. Define the key OOP terms: Class, Object, Type, Attribute, and Method.
Answer: Class: a blueprint for an instance with defined behavior. Object: an instance of a class performing the
functionality defined in it. Type: indicates which class an instance belongs to. Attribute: any value stored on an
object, accessed as [Link]. Method: a 'callable attribute' — i.e., a function defined inside a class.
Q28. What is Instantiation?
Answer: Instantiation is the process of creating an object from a class. Calling the class name like a function (e.g.,
MyClass()) creates a new instance, with each instance stored at a different memory address.
Q29. What is Attribute Lookup?
Answer: Attribute lookup is the process by which an instance looks for a requested attribute — first checking the
instance itself, then the class it was instantiated from, and then any parent classes the class inherits from.
Q30. What is an Instance Method and what role does 'self' play?
Answer: An Instance Method is a function defined inside a class that requires an instance to call it, and does not
require a decorator. The first parameter of an instance method is conventionally named 'self', which refers to the
specific instance calling the method. While it could technically be named anything, 'self' is the standard naming
convention.
Q31. What is Encapsulation?
Answer: Encapsulation hides the internal complexity of an object's working, restricting access to some of the object's
components. This means the internal representation of an object cannot be seen from outside the object's definition
— the internal state is protected.
Q32. State the advantages of Encapsulation to a developer.
Answer: Encapsulation is advantageous to the developer in two main ways: (1) It simplifies and makes it easy to
understand and use an object without needing to know its internal workings. (2) Any change to the internal
implementation can be easily managed without affecting code that uses the object from outside.
Q33. How is data protected in Encapsulation, and what are Getters and Setters?
Answer: Access to an object's private data is typically achieved through special methods called Getters (which
retrieve/return a value) and Setters (which set/assign a value). Data should only be accessed through these instance
methods rather than being directly modified from outside the class, which helps ensure the data stored remains valid.
Page 4 of 12
OOP in Python — NAUB Exam Revision Handout
Q34. What is the __init__ method (constructor)?
Answer: The __init__ method is called the constructor of a class. It is implicitly called automatically as soon as an
object of the class is instantiated, and its purpose is to initialize the object — setting up beginning attribute values or
running any setup routine required when the object is created. 'Init' stands for initialization.
Q35. Differentiate between Class Attributes and Instance Attributes.
Answer: A Class Attribute is defined directly in the class body (not inside a method) and is shared by all instances of
that class — it is not prefixed with 'self'. An Instance Attribute is defined inside a method (usually __init__) using
self, and its value is particular to each individual instance. Two different instances can have two different values for
the same instance attribute, but they all share the same class attribute value (unless overridden).
Q36. How can a Class Attribute be accessed?
Answer: A class attribute can be accessed both through the class itself ([Link]) and through any
instance of that class ([Link]), because instances have access to both their own instance attributes
and the shared class attributes.
Q37. What happens when a Class Attribute is overridden at the instance level?
Answer: When you assign a new value to a class attribute through a specific instance, Python creates a new instance
attribute with that name, which 'shadows' (hides) the class attribute for that instance only. If this overriding instance
attribute is later deleted using 'del', the attribute lookup goes back up to the class level and the original class attribute
value is used again.
SECTION 4: OBJECT ORIENTED SHORTCUTS (BUILT-IN FUNCTIONS)
Q38. What is a Built-in Function in Python?
Answer: A built-in function is a function that is part of the Python interpreter and is readily available for use without
needing to be imported. Python provides many built-in functions such as len(), dict(), help(), min(), sorted(), and
others.
Q39. What does the len() function do, and how does it work internally?
Answer: The len() function returns the length or number of items of an object such as a string, list, or collection.
Internally, it works by calling the object's own __len__() method (e.g., list.__len__()). len() only works on objects
that define a __len__() method. Programmers prefer using len() instead of calling __len__() directly because it is
more efficient, easier to maintain, and supports backward compatibility.
Q40. What does the reversed() function do?
Answer: reversed(seq) returns a reverse iterator over a sequence. The sequence must have a __reversed__() method,
or support the sequence protocol (having both __len__() and __getitem__() methods). It is commonly used in for
loops when you want to iterate over items from back to front.
Q41. What does the enumerate() function do?
Answer: enumerate() adds a counter to an iterable and returns an enumerate object. Its syntax is enumerate(iterable,
start=0), where 'start' is optional and defaults to 0. It returns an iterator that yields tuples of (index, value), and is
most useful when used within a for loop to keep track of both an item's position and its value.
Q42. Name other commonly used built-in functions for object manipulation and what they do.
Answer: hasattr(), getattr(), setattr(), and delattr() allow an object's attributes to be manipulated using their string
names. all() and any() accept an iterable and return True if all, or any, of the items evaluate to true respectively. zip()
takes two or more sequences and returns a new sequence of tuples, pairing up corresponding values from each
sequence.
Q43. Explain the open() function and its common file modes.
Answer: open(filename, mode) is used to open a file and return a file object. Common modes are: 'r' for read only
(default mode); 'w' for writing only (erases existing content); 'a' for appending (adds new data to the end of the file
without erasing it); and 'r+' for both reading and writing. On Windows, appending 'b' to a mode (e.g., 'rb', 'wb') opens
the file in binary mode.
Page 5 of 12
OOP in Python — NAUB Exam Revision Handout
Q44. Why is closing a file with close() important?
Answer: Calling close() ensures any buffered writes are actually written to disk, that the file is properly cleaned up,
and that all resources tied to the file are released back to the operating system. Although Python automatically closes
files when a script ends, it is best practice to explicitly call close().
Q45. What is Method Overloading, and how does Python achieve similar behavior without true
overloading?
Answer: Method overloading refers to having multiple methods with the same name that accept different sets of
arguments. Python does not support true method overloading like some other languages; instead, a single method can
use default arguments (e.g., name=None) so it can be called with zero, one, or more parameters, and different logic
executes depending on what was passed.
Q46. What is a Callable Object?
Answer: A callable object is any object that can accept arguments and possibly return a value when called. A
function is the simplest example of a callable object, but classes and certain class instances can also be callable. In
Python, any object that defines a __call__() method can be called using function-call syntax, just like a regular
function.
Q47. Explain the statement 'Functions are objects too' in Python.
Answer: In Python, every function is itself an object. This means attributes can be attached to a function (e.g.,
my_func.description = 'text'), and functions can be passed around as arguments to other functions, just like any other
object. Objects can contain functions, but not every object is itself a function.
SECTION 5: INHERITANCE AND POLYMORPHISM
Q48. What is Inheritance in Python?
Answer: Inheritance is a mechanism that lets a programmer create a general (base) class first and then extend it into
more specialized classes. It allows re-use of all data fields and methods available in the base class, and lets the
programmer add new methods and data fields to the derived class — organizing code rather than rewriting it from
scratch.
Q49. Define Super/Parent/Base class and Subclass/Child/Derived class.
Answer: When class X extends (inherits from) class Y, Y is called the super class, parent class, or base class, while
X is called the subclass, child class, or derived class. Only non-private data fields and methods of the base class are
accessible by the child class; private members remain accessible only inside the base class itself.
Q50. State the Object Attribute Lookup Hierarchy.
Answer: When Python looks for an attribute, it checks in this order: first the instance itself, then the class the
instance belongs to, and then any class(es) from which that class inherits.
Q51. What is Polymorphism and how does it relate to inheritance?
Answer: Polymorphism ('many shapes') is a feature used when different classes or subclasses share commonly
named methods. It permits functions to work with objects of different types without needing to know the specific
class of each object, providing flexibility and loose coupling so code can be extended and maintained easily.
Polymorphism is carried out through inheritance, where subclasses either use base class methods as-is or override
them with their own implementation.
Q52. Give an example of built-in Polymorphism in Python.
Answer: The len() function is polymorphic — it can be used with many different object types (strings, lists,
dictionaries, etc.) and returns the correct result based on whichever type of object is passed to it.
Q53. What is Method Overriding?
Answer: Method Overriding occurs when a subclass defines a method with the same name as one in its superclass,
replacing (overriding) the superclass's version. The overridden superclass method can still be called explicitly using
super(Subclass, self).method() instead of [Link]().
Q54. How does Constructor Inheritance work in Python?
Answer: If a child class does not define its own __init__ method, Python uses attribute lookup to search for __init__
in the parent class and calls it there. If the child class complexity grows, the child's own __init__ can call the parent's
Page 6 of 12
OOP in Python — NAUB Exam Revision Handout
constructor using super() to first initialize the parent's attributes, then set up its own — this avoids code duplication
and keeps the class hierarchy easy to change.
Q55. Summarize the key conclusions about __init__ and inheritance.
Answer: __init__ is like any other method and can be inherited. If a class has no __init__, Python checks its parent
class for one, and stops looking as soon as it finds one to call. The super() function can be used to call methods
(including __init__) in the parent class. Sometimes both the parent and child classes need their own initialization
logic.
Q56. What is Multiple Inheritance?
Answer: Multiple Inheritance is when a class inherits from more than one parent class. To create a class with
multiple parents, the names of the parent classes are listed inside parentheses, separated by commas, when defining
the derived class.
Q57. What is the Method Resolution Order (MRO), and which search strategy does Python use by
default?
Answer: The Method Resolution Order (MRO) is the order in which Python searches classes (instance, class, parent
class, grandparent class, and so on) to find a requested attribute or method when multiple inheritance is involved. By
default, Python uses a depth-first search order to resolve this.
Q58. Explain the 'Diamond Problem' in multiple inheritance and how Python resolves it.
Answer: The Diamond Problem occurs when two classes both inherit from the same class, and a further class inherits
from both of them — creating an ambiguous inheritance diagram shaped like a diamond. Python resolves this by
removing earlier duplicate appearances of a repeated class from the MRO — if the same class appears more than
once in the resolution order, only its last (most specific) appearance is kept.
Q59. List the conclusions about Multiple Inheritance.
Answer: Any class can inherit from multiple classes. Python normally uses a depth-first order when searching
inheriting classes. However, when two classes inherit from the same class, Python removes the first (earlier)
appearance of that shared class from the MRO to avoid ambiguity.
Q60. Differentiate between an Instance Method, a Class Method, and a Static Method.
Answer: An Instance Method's first argument is 'self' (the instance) and can access/modify instance state. A Class
Method uses the @classmethod decorator and its first argument is 'cls' (the class) — it can modify class state shared
across all instances, but cannot modify a specific object's instance state. A Static Method uses the @staticmethod
decorator, takes neither 'self' nor 'cls', and can modify neither instance state nor class state — it is restricted in what
data it can access.
Q61. When should Class Methods versus Static Methods be used?
Answer: Class methods are generally used to create factory methods — methods that return a class object for
different use cases, similar to an alternate constructor. Static methods are generally used to create utility functions
that logically belong to the class but don't need access to instance or class data.
SECTION 6: PYTHON DESIGN PATTERNS
Q62. What is a Software Design Pattern?
Answer: A design pattern is an almost standardized way of coding a particular logic, mechanism, or technique in
software. Just as physical products (like cars) follow a repeated design pattern, software problems that recur often
have a proven, well-documented solution approach — this is what a design pattern captures.
Q63. Why are Design Patterns important? State their benefits.
Answer: Design patterns: help solve common design problems using a proven approach; remove ambiguity because
they are well documented; reduce overall development time; make future extensions and modifications easier; and
may reduce errors since they are proven solutions to common problems.
Q64. How are Design Patterns classified? (Name the GoF categories)
Answer: The Gang of Four (GoF) classify design patterns into three categories: Creational, Structural, and
Behavioral patterns.
Page 7 of 12
OOP in Python — NAUB Exam Revision Handout
Q65. What are Creational Design Patterns? Name examples.
Answer: Creational patterns separate the logic of object creation from the rest of the system — instead of the
programmer directly creating objects, creational patterns create them. Examples include Abstract Factory, Builder,
Factory Method, Prototype, and Singleton. These are less commonly used in Python because the language's dynamic
nature already provides much of this flexibility.
Q66. What are Structural Design Patterns? Name examples.
Answer: Structural patterns help build larger structures from existing sets of classes rather than starting from scratch.
Structural class patterns use inheritance to build new structures, while structural object patterns use
composition/aggregation for new functionality. Examples include Adapter, Bridge, Composite, Decorator, Façade,
Flyweight, and Proxy.
Q67. What are Behavioral Design Patterns? Name examples.
Answer: Behavioral patterns offer the best ways of handling communication between objects, describing the
functionality of a system. Examples include Visitor, Chain of Responsibility, Command, Interpreter, Iterator,
Mediator, Memento, Observer, State, Strategy, and Template Method.
Q68. Explain the Singleton Design Pattern and where it is used.
Answer: The Singleton pattern ensures that a class has only one shared instance, and that instance is reused every
time the class is 'constructed', rather than creating a new object each time. It is used when: logging needs to be
implemented and the logger instance must be shared across the whole system; configuration files need a shared cache
of information across components; and when managing a single shared connection to a database.
SECTION 7: ADVANCED FEATURES
Q69. What are Magic Methods (Dunder Methods) in Python?
Answer: Magic methods are special built-in methods, surrounded by double underscores (e.g., __add__, __len__,
__repr__), that Python calls automatically behind the scenes when certain operators or built-in functions are used.
For example, var1 + var2 internally calls var1.__add__(var2). Custom classes can define these magic methods to
make instances work naturally with standard operators and functions.
Q70. Give examples of operations and the magic methods they map to internally.
Answer: 'abc' in var calls var.__contains__('abc'). var == 'abc' calls var.__eq__('abc'). var[1] calls
var.__getitem__(1). var[1:3] calls var.__getslice__(1,3). len(var) calls var.__len__(). print(var) calls var.__repr__().
Q71. Can a class inherit from a Python built-in type? Explain.
Answer: Yes. A class can inherit from built-in types such as dict or list, gaining all their existing functionality. The
class can then override specific magic methods, such as __setitem__ or __getitem__, to customize how the inherited
built-in behaves — for example, changing list indexing to start at 1 instead of 0.
Q72. What is PEP 8 and who created it?
Answer: PEP 8 is a style guide written by Guido van Rossum, the creator of Python, that describes best practices for
naming and coding style. PEP stands for Python Enhancement Proposal — a series of documents distributed within
the Python community to discuss proposed changes and standards.
Q73. State the recommended PEP 8 naming conventions.
Answer: Module names: all_lower_case. Class names and exception names: CamelCase. Global and local variable
names: all_lower_case. Function and method names: all_lower_case. Constants: ALL_UPPER_CASE. These are
recommendations, not enforced rules, but following them makes code more familiar and readable to other
developers.
Q74. Why should developers conform to PEP 8 naming conventions?
Answer: Following PEP 8 conventions makes code more familiar to the majority of developers, clearer to readers,
consistent with the style of other contributors on the same codebase, and is considered a mark of a professional
software developer.
Q75. Explain how Python denotes 'Public' and 'Private' variables, given there is no true privacy.
Answer: Python has no true 'private' variables that are completely inaccessible from outside an object — privacy is
achieved only through naming convention. Public attributes use regular_lower_case naming. Private attributes (for
Page 8 of 12
OOP in Python — NAUB Exam Revision Handout
internal use) are prefixed with a single leading underscore: _single_leading_underscore. Attributes meant not to be
subclassed use a double leading underscore: __double_leading_underscore (this triggers 'name mangling'). Magic
attributes use double underscores on both sides: __double_underscores__, and should be used but not created by
programmers.
SECTION 8: STRINGS
Q76. Why are Strings widely used in programming?
Answer: Strings are one of the most popular data types because humans naturally understand and communicate using
text and words rather than raw numbers. In programming, strings are used for parsing text, analyzing text semantics,
and data mining involving human-readable content.
Q77. Are Strings mutable or immutable in Python?
Answer: Strings in Python are immutable — once created, a string's contents cannot be changed. Any operation that
appears to modify a string actually creates and returns a new string.
Q78. Name common String methods and their purpose.
Answer: isalpha() checks if all characters are alphabetic. isdigit() checks for digit characters. isdecimal() checks for
decimal characters. isnumeric() checks for numeric characters. find() returns the index of a substring. istitle() checks
for title-cased strings. join() concatenates strings together. lower()/upper() convert case. partition() splits a string into
a tuple of three parts.
Q79. What is String Formatting and what are the two main approaches?
Answer: String formatting inserts values into a string template. It can be done using the [Link]() method, where
replacement fields are marked with curly braces { } (which can contain a positional index or keyword name), or
using the older % sign style formatting.
Q80. What does it mean that Python strings are 'Unicode'?
Answer: Python strings are collections of immutable Unicode characters, meaning they can represent virtually any
character from any language or symbol set — not just basic ASCII characters. This allows software written in Python
to work correctly across different languages and regions.
Q81. Differentiate between Encoding and Decoding.
Answer: Encoding is the process of converting a string (text) into a bytes object, implemented with the encode()
method (default technique is UTF-8). Decoding is the reverse process — converting a bytes object back into a text
string — implemented with the decode() method. Encoding and decoding are inverse operations of each other, and
you must know which encoding was used originally to decode correctly.
Q82. List the standard order of operations for File I/O in Python.
Answer: A file operation in Python follows three steps: (1) Open the file, (2) Read from or write to the file, (3) Close
the file. Python wraps the underlying byte stream with appropriate encode/decode calls, allowing programmers to
work directly with str objects for text files.
SECTION 9: EXCEPTIONS AND EXCEPTION HANDLING
Q83. What is an Exception in programming?
Answer: An exception is any unusual condition that occurs during program execution. Exceptions usually indicate
errors, but are sometimes used intentionally, such as terminating a procedure early or recovering from a resource
shortage. Python has many built-in exception types identifying specific error conditions.
Q84. What are the two components of Exception Handling?
Answer: Exception handling has two components: 'throwing' (raising an exception when an error condition occurs)
and 'catching' (handling that exception gracefully so the program can respond meaningfully rather than crashing).
Page 9 of 12
OOP in Python — NAUB Exam Revision Handout
Q85. Explain common built-in Exception types and what triggers them.
Answer: ZeroDivisionError occurs when dividing by zero. NameError occurs when referencing a variable that has
not been defined (often due to misspelling). SyntaxError occurs when the code violates Python's grammar rules (e.g.,
an unclosed quote). KeyError occurs when trying to access a dictionary key that does not exist. IndexError occurs
when trying to access a list index that is out of range.
Q86. Explain the try/except mechanism for catching exceptions.
Answer: The try and except keywords are used to catch exceptions. Code that might raise an exception is placed
inside the try block. If an exception occurs, the rest of the try block is skipped, and Python looks for a matching
except block to handle the specific exception type — execution then jumps there.
Q87. How do you raise your own exception in Python?
Answer: The 'raise' keyword is used to explicitly raise an exception from your own code, using the syntax: raise
ExceptionClass('Some message here'). This immediately stops normal execution and looks for a matching except
block to handle it.
Q88. How can a Custom Exception class be created?
Answer: A custom exception class is created by extending (subclassing) the BaseException class or one of its
subclasses (such as RuntimeError or Exception). The custom class typically defines its own __init__ constructor,
often calling the parent's constructor with super().__init__(), and can add its own attributes such as extra error
details.
Q89. Describe the top of the built-in Exception class hierarchy.
Answer: At the very top of Python's exception hierarchy is BaseException. Its direct subclasses include SystemExit,
KeyboardInterrupt, GeneratorExit, and Exception. The Exception class is the parent of most commonly encountered
error types, including ArithmeticError, AttributeError, LookupError (parent of IndexError and KeyError),
NameError, OSError, RuntimeError, SyntaxError, TypeError, and ValueError.
SECTION 10: OBJECT SERIALIZATION
Q90. What is Serialization?
Answer: Serialization is the process of translating a data structure or an object's state into a format that can be stored
(e.g., in a file or memory buffer) or transmitted, and later reconstructed. The reverse process, converting the
stored/transmitted format back into the original object, is called Deserialization.
Q91. What is Pickling and Unpickling?
Answer: Pickling is the process of converting a Python object hierarchy into a byte stream (usually not human-
readable) so it can be written to a file — this is Python's built-in form of serialization. Unpickling is the reverse
process, converting a byte stream back into a working Python object hierarchy.
Q92. What can the Pickle module do, and what are its limitations?
Answer: Pickle can easily store and reproduce dictionaries and lists, and it stores an object's attribute values and
restores them to the same state later. However, pickle does NOT save an object's actual code — only its attribute
values — and it cannot store file handles or connection sockets.
Q93. Name the four main methods of the Pickle interface.
Answer: dump() serializes an object to an open file (file-like object). dumps() serializes an object to a string. load()
deserializes an object from an open file-like object. loads() deserializes an object from a string.
Q94. What is JSON and why is it popular?
Answer: JSON (JavaScript Object Notation) is a lightweight, human-readable data-interchange format that is part of
the Python standard library. It is easy for humans to read and write, and easy for programs to parse and generate. Its
human-readable nature and simplicity make it very popular for data transmission and working with web APIs.
Q95. Compare Pickle and JSON.
Answer: Pickle output is a byte stream that is not human-readable, while JSON output is human-readable, structured
text. JSON is commonly used for data exchange (especially over the web/APIs) because of its readability, whereas
Pickle is more specific to Python-to-Python object storage.
Page 10 of 12
OOP in Python — NAUB Exam Revision Handout
Q96. What is YAML, and what advantages does it offer over JSON?
Answer: YAML is considered one of the most human-friendly data serialization formats. Its Python module is called
pyaml. YAML offers: highly human-readable code; compact code that uses whitespace indentation instead of
brackets to denote structure; support for relational data through anchors (&) and aliases (*); and wide use for
configuration files, debugging dumps, and document headers.
Q97. What is PDB and what is a Breakpoint?
Answer: PDB (the Python Debugger) is a built-in module that supports setting breakpoints in a program. A
breakpoint is an intentional pause in the program's execution (set using pdb.set_trace()) that allows the programmer
to inspect the program's current state — such as variable values — during debugging.
Q98. What is Logging in Python?
Answer: The logging module has been part of Python's Standard Library since Python version 2.3. Because it is a
built-in module, every Python module can participate in logging, allowing an application's log to include its own
messages integrated with messages from third-party modules. It provides a lot of flexibility and functionality for
recording what a program is doing.
Q99. State the benefits of Logging.
Answer: Logging provides two main benefits: (1) Diagnostic logging — it records events related to the application's
own operation, useful for troubleshooting. (2) Audit logging — it records events for business analysis purposes.
Q100. List the logging severity levels from lowest to highest, and their integer values.
Answer: DEBUG (10) — diagnostic messages for development. INFO (20) — standard progress messages.
WARNING (30) — a detected non-serious issue (this is the default level if none is set). ERROR (40) — an error has
occurred, possibly serious. CRITICAL (50) — usually a fatal error that stops the program.
Q101. What is Benchmarking (Profiling) and which module is used for it?
Answer: Benchmarking (or profiling) tests how fast code executes and identifies performance bottlenecks, mainly
for the purpose of optimization. Python's built-in timeit module is used for this — it times small code snippets using
platform-specific time functions to get the most accurate timing possible, and allows comparison between different
implementations to determine which performs better.
Page 11 of 12
OOP in Python — NAUB Exam Revision Handout
QUICK-GLANCE REVISION: KEY DEFINITIONS
Term One-Line Meaning
Class A blueprint/factory for creating objects; defines attributes and methods.
Object/Instance A specific realization of a class, created via instantiation.
Encapsulation Hiding internal details/data of an object behind a clean interface.
Inheritance A class (child) acquiring attributes/methods of another class (parent).
Abstraction Hiding implementation details, showing only essential features.
Polymorphism Same method name behaving differently across different classes.
self Refers to the current instance inside an instance method.
__init__ The constructor; runs automatically when an object is created.
Class Attribute Shared by all instances; defined directly in the class body.
Instance Attribute Specific to one object; defined using self inside a method.
super() Built-in function used to call a method from the parent class.
MRO Method Resolution Order — the order Python searches classes for attributes.
@classmethod Decorator for methods whose first argument is the class (cls).
@staticmethod Decorator for methods needing no access to self or cls.
Pickling Converting a Python object into a byte stream for storage.
Serialization Converting an object/data structure into a storable/transmittable format.
Exception An unusual condition/error raised during program execution.
try/except Block structure used to catch and handle exceptions gracefully.
PEP 8 Python's official style guide for naming and code conventions.
Design Pattern A proven, reusable solution approach to a common software design problem.
Page 12 of 12