- class keyword defines a new class
- __init__ is the constructor
- self refers to the current instance
- Methods define object behavior
This presentation is designed for desktop or projector displays.
← Back to curriculumPYTHON OOP — COURSE 12
Everything we've covered — in 9 quick stops
← → to navigate
Where we are in the journey
Topic 1
Quick recap, then quizzes from the exam pool
The data each object will hold
self.title = title self.author = author self.year = year
The behavior each object can perform
def display_info(self): print(f"{self.title}")
class Book: def __init__(self, title, author, year): self.title = title self.author = author self.year = year def display_info(self): print(f"{self.title} by {self.author} ({self.year})")
Syntax:
object_name = ClassName(parameters)
Example:
book1 = Book("Clean Code", "Robert Martin", 2008) book2 = Book("Refactoring", "Martin Fowler", 1999)
person1.introduce()
Person.introduce(person1)
Called by len(obj)
Returns length/size of object
Called by obj1 + obj2
Defines addition behavior
Called by print(obj)
String representation
What is a class in programming?
A) A specific instance of an object
B) A template for creating objects
C) A type of function in a program
D) A variable that holds data
A class is a template (blueprint) for creating objects. Each object built from a class shares the same structure but has its own data.
Which statement best describes an object in OOP?
A) A function that performs a specific task
B) A prototype for classes
C) An instance of a class
D) A collection of classes
An object is an instance of a class. The class defines the structure; the object holds the actual data and can call the methods.
Which of these is NOT one of the four pillars of OOP?
A) Encapsulation
B) Abstraction
C) Compilation
D) Polymorphism
The four pillars are Abstraction, Encapsulation, Inheritance, Polymorphism. Compilation is unrelated — it's a build step, not an OOP concept.
Topic 2
Quick recap, then quizzes from the exam pool
The core characteristics of object-oriented programming
🛡
Abstraction
Hide complexity, show essentials
🔒
Encapsulation
Bundle data & restrict access
🔁
Polymorphism
One interface, many forms
📂
Inheritance
Reuse & extend existing code
Python uses naming conventions, not strict enforcement
| Prefix | Level | Meaning |
|---|---|---|
name |
Public | Accessible from anywhere |
_name |
Protected | Convention: internal use only |
__name |
Private | Name mangling applied |
| Feature | Public | Protected _ | Private __ |
|---|---|---|---|
| Access from outside | ✓ | ✓ (discouraged) | ✗ (mangled) |
| Access from subclass | ✓ | ✓ | ✗ (mangled) |
| Enforced by Python | N/A | No (convention) | Partially |
| Use case | API / interface | Internal logic | Avoid name clashes |
Same thing, but Pythonic
class MyClass: def __init__(self, value): self._value = value @property def value(self): return self._value @value.setter def value(self, new_value): if new_value >= 0: self._value = new_value obj = MyClass(10) print(obj.value) # 10 (uses getter) obj.value = 20 # uses setter
import math class Circle: def __init__(self, radius): self._radius = radius @property def radius(self): return self._radius @radius.setter def radius(self, value): if value <= 0: raise ValueError("Radius must be positive") self._radius = value @property def area(self): return math.pi * self._radius ** 2 c = Circle(5) print(c.area) # 78.54 (computed property)
What does encapsulation refer to in object-oriented programming?
A) The process of inheriting properties from a base class
B) The practice of keeping data and the methods that modify it together within a class
C) Dividing a program into multiple distinct classes
D) The interaction between different objects
Encapsulation bundles data + the methods that operate on that data inside a single class — and hides internals from outside code.
In Python, which prefix is used to declare a private variable?
A) private
B) protect
C) __ (double underscore)
D) private:
Python uses naming conventions: a double underscore prefix triggers name-mangling (private-ish). Single underscore _x is just a convention for «protected».
How are private variables of a Python class typically accessed from outside?
A) Directly by their name
B) They cannot be accessed at all
C) Through reflection library functions
D) Through public methods (getters / setters) defined in the class
The Pythonic way: expose public methods (or @property) that act as getters/setters. This keeps the internal data hidden and gives you a place to validate writes.
Topic 3
Quick recap, then quizzes from the exam pool
Real-world hierarchies map to code
The class from which properties and methods are inherited. Also known as a "parent" class.
The class that inherits from another class. Can add new properties or modify existing ones. Also known as a "child" class.
Allows creation of a new class that is a modified version of an existing class.
class Animal: # Parent class def eat(self): print("This animal is eating") class Dog(Animal): # Child class def bark(self): print("The dog barks") class Cat(Animal): # Child class def meow(self): print("The cat meows") rex = Dog() rex.eat() # This animal is eating rex.bark() # The dog barks
class Dog(Animal) — the parentheses declare the inheritance relationship
__init__ in InheritanceHow constructors chain through the hierarchy
Child's __init__ overrides parent's. Parent attributes are lost!
class Animal: def __init__(self, name): self.name = name class Dog(Animal): def __init__(self, name, breed): self.breed = breed # name is LOST! rex = Dog("Rex", "Labrador") print(rex.breed) # Labrador print(rex.name) # AttributeError!
Call super().__init__() to chain constructors
class Animal: def __init__(self, name): self.name = name class Dog(Animal): def __init__(self, name, breed): super().__init__(name) self.breed = breed rex = Dog("Rex", "Labrador") print(rex.name) # Rex ✔ print(rex.breed) # Labrador ✔
super().__init__() when overriding the constructorA subclass provides a specific implementation for a method already defined in its superclass
Subclasses tailor or modify inherited behavior without altering the superclass code
Subclasses can extend behavior by adding steps and calling super()
A single interface can represent different underlying forms
Access superclass methods — ensures proper initialization
class Animal: def __init__(self, name): self.name = name class Dog(Animal): def __init__(self, name, breed): super().__init__(name) self.breed = breed
super() can call any method from the parent class, not just the constructor.
How would you call the constructor of the parent class from a child class in Python?
A) Using the parent keyword
B) Using the super() function
C) Using the self keyword
D) Using both self and super()
super().__init__(...) chains to the parent constructor. Without it, parent attributes never get initialised — you'll hit AttributeError later.
Which terms are valid synonyms for «parent class»? (select all that apply)
A) Base class
B) Subclass
C) Derived class
D) Superclass
Parent / Base / Super — same thing. Child / Sub / Derived — same thing. Don't mix them up on the exam.
What problem can occur when using multiple inheritance?
A) Diamond problem
B) Circle inheritance
C) Random resolution
D) Memory leak
The Diamond problem — a class inherits from two classes that share a common ancestor, creating ambiguity about which method to call. Python resolves this with the MRO.
Topic 4
Quick recap, then quizzes from the exam pool
A fundamental OOP concept where objects of different classes can be treated as objects of a common super class
class Animal: def speak(self): pass class Dog(Animal): def speak(self): return "Woof!" class Cat(Animal): def speak(self): return "Meow!" animals = [Dog(), Cat(), Dog(), Cat()] for animal in animals: print(animal.speak())
Woof! Meow! Woof! Meow! — same method call, different behavior!
class Duck: def quack(self): print("Quack!") class Person: def quack(self): print("I can quack too!") def make_it_quack(thing): thing.quack() make_it_quack(Duck()) make_it_quack(Person())
make_it_quack() doesn't care about the type — only that the object has a quack() method
from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def area(self): pass @abstractmethod def perimeter(self): pass class Circle(Shape): def __init__(self, radius): self.radius = radius def area(self): return 3.14159 * self.radius ** 2 def perimeter(self): return 2 * 3.14159 * self.radius
Shape() raises TypeError — you must use a concrete subclass like Circle(5)
What is polymorphism in Python?
A) A method always does the same thing regardless of the object
B) Accessing properties of one class from another class
C) A method does different things based on the object that it is acting upon
D) Inheriting properties and methods from another class
Polymorphism — one interface, many forms. Same method call (animal.speak()), different result depending on the object's actual class.
Which decorator is used to define an abstract method in Python?
A) @abstract
B) @abstractdecorator
C) @abstractmethod
D) @override
Use @abstractmethod from the abc module. The class itself must inherit from ABC — then it can't be instantiated until all abstract methods are implemented.
What is method overriding?
A) Deleting a method from a parent class
B) Modifying an existing method in the parent class
C) Creating a new method in a child class with the same name but different parameters
D) Creating a new method in a child class with the same name and parameters
Overriding — same signature, new implementation in the child class. (Different parameters = overloading, which Python doesn't natively support.)
Topic 5
Quick recap, then quizzes from the exam pool
Two fundamental types
A subclass is a type of its parent
An object has a reference to another object
class Engine: def __init__(self, horsepower): self.horsepower = horsepower def start(self): return "Engine running" class Car: def __init__(self, model): self.model = model self.engine = Engine(200) def drive(self): return self.engine.start()
Car creates the Engine inside __init__Car object is deleted, the Engine goes with it# Usage my_car = Car("Toyota") print(my_car.drive()) # Engine running
| Composition | Aggregation | |
|---|---|---|
| Relationship | Strong "has-a" | Weak "has-a" |
| Ownership | Exclusive | Shared |
| Lifecycle | Parts die with owner | Parts live independently |
| Creation | Created inside owner | Passed in from outside |
| Coupling | Tight | Loose |
| Example | House & Rooms | Team & Players |
A principle suggesting classes should achieve polymorphism through composition rather than inheritance
Which relationship best describes composition in OOP?
A) is-a
B) can-do
C) uses-a
D) has-a
Composition is a has-a relationship (Car has-a Engine). Inheritance is is-a (Dog is-a Animal).
Which is a key difference between aggregation and composition?
A) In aggregation, the part can exist independently of the whole
B) In composition, objects are linked using pointers
C) Aggregation implies stronger ownership than composition
D) There is no real difference
Composition = parts die with the owner (House & Rooms). Aggregation = parts survive independently (Team & Players).
A Car class creates and owns an Engine object inside its __init__. This is an example of...
A) Aggregation
B) Composition
C) Inheritance
D) Dependency injection
Creating the part inside the owner and tying its lifecycle to the owner = composition. If Engine were passed in from outside, that would be aggregation / DI.
Topic 6
Quick recap, then quizzes from the exam pool
Exception handling is a programming mechanism that enables developers to manage errors and anomalies that arise during the execution of a program.
In essence, it allows a program to continue running or gracefully terminate when it encounters unexpected situations, rather than crashing abruptly.
The finally keyword in the try-except block is always executed, irrespective of whether there is an exception or not.
It is quite useful in cleaning up resources and closing the object, especially closing the files.
try: # Code that might raise an exception except ExceptionType: # Code that runs if an exception occurs finally: # Cleanup code that runs no matter what
Custom exceptions are defined by subclassing Python's built-in Exception class.
The simplest form:
class MyCustomError(Exception): pass
With a constructor:
class ValidationError(Exception): def __init__(self, message, value): self.message = message self.value = value super().__init__(message)
2023-04-01 09:15:30 - root - DEBUG - This is a debug message 2023-04-02 10:20:45 - root - INFO - This is an info message 2023-04-03 11:25:50 - root - WARNING - This is a warning message 2023-04-04 12:30:55 - root - ERROR - This is an error message 2023-04-05 13:35:00 - root - CRITICAL - This is a critical message
Which keyword is used immediately after try to catch exceptions in Python?
A) catch
B) except
C) finally
D) error
except. (Java/C# use catch, but Python uses except.) You can specify the exception type: except ValueError:
Which block always runs, whether or not an exception occurred?
A) except
B) finally
C) else
D) before
finally always runs — ideal for cleanup like closing files or releasing locks. else only runs if no exception was raised.
Which keyword is used to manually raise an exception in Python?
A) throw
B) raise
C) error
D) exception
raise — e.g. raise ValueError("negative balance"). Java/C# use throw; Python uses raise.
When writing a custom exception in Python, which class should you derive from?
A) Error
B) Exception
C) BaseError
D) CustomError
Inherit from Exception (or a more specific subclass like ValueError). Avoid inheriting from BaseException directly — that catches things like KeyboardInterrupt.
Topic 7
Quick recap, then quizzes from the exam pool
We want to:
How well the internal elements of a module work together to fulfill a single, well-defined purpose.
The degree of direct knowledge or reliance one module has on another. Lower is better.
Substitutable = capable of being exchanged.
Users of a base class should continue to function properly if a derivative of that base class is passed to it.
💡 If you have a function that works with Animal, it should also work with Dog (which is a type of Animal) without needing any special adjustments.
Ensure that your classes only implement the methods they need. If a class is forced to implement methods it doesn't use, consider breaking your interface (or ABC) into smaller, more specific ones.
Which SOLID principle states that a class should have only one reason to change?
A) Single Responsibility Principle
B) Open/Closed Principle
C) Liskov Substitution Principle
D) Dependency Inversion Principle
SRP — one class, one responsibility. If two unrelated reasons could force you to edit the same class, split it.
Which SOLID principle states that a class should be open for extension and closed for modification?
A) Single Responsibility Principle
B) Open/Closed Principle
C) Liskov Substitution Principle
D) Dependency Inversion Principle
OCP — you should be able to add new behavior (extend) without rewriting existing code (modify). Achieved via inheritance, composition, or strategy patterns.
Which SOLID principle states that objects of a superclass should be replaceable with objects of its subclasses without breaking the application?
A) Single Responsibility Principle
B) Open/Closed Principle
C) Liskov Substitution Principle
D) Dependency Inversion Principle
LSP — named after Barbara Liskov. If code expects an Animal, passing a Dog should still work correctly. Penguins shouldn't break a Bird.fly() contract.
Which statements about the Dependency Inversion Principle (DIP) are correct? (select all that apply)
A) High-level modules should not depend on low-level modules
B) Low-level modules should not depend on high-level modules
C) Both should depend on abstractions, not on concrete classes
D) Abstractions should depend on details (concrete classes)
DIP has two halves: high-level code shouldn't depend on low-level code, and both should depend on abstractions. Dependency injection is one common technique for following DIP.
Topic 8
Quick recap, then quizzes from the exam pool
A standardized solution to a commonly occurring problem in software design.
They are templates, not ready-made code. You adapt the pattern to fit your specific problem.
🏭
How objects are created
🧩
How objects are composed
💬
How objects communicate
class DatabaseSingleton: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) cls._instance.connection = "Connected to DB" return cls._instance def query(self, sql): return f"Executing: {sql}"
✅ How it works:
_instance stores the single object (starts as None)__new__ checks: if no instance exists → create one; otherwise → return existingDatabaseSingleton() returns the same objectWhich describes the role of the Factory Method pattern?
A) Defines the skeleton of an algorithm
B) Creates objects without specifying the exact class
C) Allows classes to work together that couldn't otherwise
D) Provides global access to a single instance
Factory Method — centralizes object creation so callers ask «what» they need, and the factory decides «which class». («Global access» describes Singleton; «classes that couldn't work together» describes Adapter.)
Which design pattern is used to construct complex objects step by step?
A) Decorator
B) Singleton
C) Builder
D) Proxy
Builder — useful when an object has many optional parameters or a multi-step construction process. Call .withX().withY().build() instead of a 12-arg constructor.
What is the purpose of the __new__ method in Python?
A) Initializing the newly created object
B) Creating and returning a new instance of a class
C) Calling after __init__ to set up the object
D) Cleaning up the object after it is no longer needed
__new__ creates and returns the instance; __init__ then initialises it. Overriding __new__ is how the Singleton pattern is typically implemented in Python.
Imagine you have to get to the airport. Different strategies:
Wearing layers of clothing:
▶ The diagram on the right shows Factory Method (GoF) — a polymorphic variant with subclass overrides. In Python, the Simple Factory below (a single create() with if/else) is what you'll use 95% of the time.
In practice — many params → one of many classes:
class TransportFactory: @staticmethod def create(destination, weight, urgent): if destination == "overseas": return Ship(weight) if urgent and weight < 10: return Drone(weight) if weight > 1000: return Train(weight) return Truck(weight) t = TransportFactory.create("overseas", 50, False)
Think of a YouTube channel:
| Pattern | Use when… |
|---|---|
| Strategy | You have several algorithms doing the same thing and want to pick at runtime |
| Decorator | You need to add behavior to an object without subclassing |
| Factory | Object creation logic shouldn't live in the caller |
| Facade | Client code is drowning in subsystem complexity |
| Iterator | You want to traverse a collection without exposing internals |
| Observer | Multiple objects must react to a state change |
Which design pattern allows behavior to be added to an individual object, dynamically?
A) Adapter
B) Observer
C) Decorator
D) Factory
Decorator — wraps an object to add behavior at runtime, without subclassing. Think of layering clothes: t-shirt → sweater → jacket → raincoat.
Which patterns organize classes and objects to form larger structures and help keep parts of the system loosely coupled?
A) Creational
B) Structural
C) Behavioral
D) Concurrency
Three GoF families: Creational (how objects are made), Structural (how they're composed — Adapter, Decorator, Facade, Proxy), Behavioral (how they communicate).
Which of these are creational design patterns? (select all that apply)
A) Factory
B) Builder
C) Adapter
D) Singleton
Creational patterns deal with object creation: Singleton, Factory, Abstract Factory, Builder, Prototype. Adapter is structural — it adapts one interface to another.
Topic 9
Quick recap, then quizzes from the exam pool
Arrange — Act — Assert. Three lines, three responsibilities.
def test_rectangle_area(): rect = Rectangle(10, 20) # Arrange area = rect.area() # Act assert area == 200 # Assert
unittest:
import unittest from rectangle import Rectangle class TestRectangle(unittest.TestCase): def test_area(self): rect = Rectangle(10, 20) self.assertEqual(rect.area(), 200)
pytest:
from rectangle import Rectangle def test_area(): rect = Rectangle(10, 20) assert rect.area() == 200
✅ Same behavior, half the code.
TDD is a development practice where you write tests before the code they test.
Three steps. Endless cycles.
What are the main phases of test-driven development (TDD)?
A) Plan, develop, test
B) Red, green, refactor
C) Design, implement, test
D) Red, green, review
Red — write a failing test. Green — make it pass with minimal code. Refactor — clean up while keeping tests green. Repeat.
What is the primary purpose of unit testing?
A) To test the entire system as a whole
B) To test individual units or components of the software
C) To test the performance of the software
D) To evaluate the usability of the software
Unit tests check one small piece (usually a method or class) in isolation. Whole-system tests are integration / end-to-end tests — different layer of the pyramid.
Which frameworks are commonly used for unit testing in Python? (select all that apply)
A) pythontest
B) pytest
C) unittest
D) pythontesting
unittest ships with the standard library. pytest is the community favorite — less boilerplate, plain assert, great fixtures.
Which statement about mocking in software testing is correct?
A) Mocking complicates testing as it requires extra mock objects
B) Mocking uses real objects in tests to ensure accuracy
C) Mocking creates full copies of objects for testing
D) Mocking simplifies testing by replacing complex dependencies with mock objects
Mocks replace slow or external things (databases, HTTP, time) with controllable fakes. The test becomes fast, deterministic, and focused on the unit you actually want to test.
self_/__ and @propertyclass Child(Parent), chain with super()try / except / else / finally, raise your own when needed__init__, self, magic methodsOn class computers in the lab.
No personal laptops, phones, or notes.
35 minutes
Read every question twice — don't get stuck on one.
20 questions
Multiple choice — some single-answer, some multi-select.
~1 min 45 s per question
Skip the hard ones first, come back at the end.
Consultation for all groups: 2026-05-15, 08:30, P2 153 · Exam venue: P2 203
| Date | Time | Group |
|---|---|---|
| Tue 2026-06-02 | 08:30 | Ef-25/1 |
| 10:20 | EEf-25/2 | |
| 12:10 | EEf-25/1 | |
| Tue 2026-06-09 | 08:30 | Ef-25/2 |
| 10:20 | EIf-25 | |
| 11:10 | EDIf-25/1 | |
| 12:10 | EAf-25 | |
| 14:30 | EKf-25 | |
| Wed 2026-06-10 | 10:20 | EDIf-25/2 |
| 12:10 | EIRf-25 |
Subject: Objektinis programavimas (su kursiniu darbu) · Code: FMSAB23201 · Type: E
Good luck on the exam — you've got this.
Questions? Ask now — this is your last chance before the exam.