0% found this document useful (0 votes)
3 views

DS Python Chapter 1 Notes

The document provides an overview of Procedural-Oriented Programming (POP) and Object-Oriented Programming (OOP), highlighting their key concepts, features, advantages, and disadvantages. It explains essential OOP concepts such as encapsulation, abstraction, inheritance, and polymorphism, along with practical examples to illustrate these principles. Additionally, it compares POP and OOP in terms of their paradigms, main focus, code structure, data handling, reusability, scalability, security, and examples of programming languages.

Uploaded by

indiandj432
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

DS Python Chapter 1 Notes

The document provides an overview of Procedural-Oriented Programming (POP) and Object-Oriented Programming (OOP), highlighting their key concepts, features, advantages, and disadvantages. It explains essential OOP concepts such as encapsulation, abstraction, inheritance, and polymorphism, along with practical examples to illustrate these principles. Additionally, it compares POP and OOP in terms of their paradigms, main focus, code structure, data handling, reusability, scalability, security, and examples of programming languages.

Uploaded by

indiandj432
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 33

1.

Introduction to OOP Concepts & Data Structures


Procedural-Oriented Programming (POP)
Procedural-Oriented Programming (POP) is a programming paradigm emphasizing a step-
by-step, sequential approach to solving problems using procedures or functions. In POP, the
primary focus is on functions (or methods) and code blocks designed to perform specific
tasks. Data and functions are separate, and the program is executed by calling these
functions in the desired order.

Key Features of POP:


1. Linear Execution: Programs follow a sequential flow, dividing tasks into smaller
functions or procedures.
2. Function-Centric: Functions are the main building blocks. They process data and
perform specific tasks.
3. Global Data Sharing: Data is often shared globally and accessed by multiple
functions, making it less secure.
4. No Encapsulation: Data and functions are not bound together, leading to less
modularity.
5. Reusable Code: Functions can be reused, but there are limited tools for modularity
compared to OOP.
6. Examples of Languages: C, Pascal, FORTRAN, and BASIC are procedural
programming languages.

Advantages of POP:
1. Simplicity: Easy to learn and implement, especially for small programs.
2. Efficient for Small Tasks: Suitable for simple problems where the step-by-step
approach is sufficient.
3. Reusable Functions: Commonly used functions can be reused in different program
parts.

Disadvantages of POP:
1. Scalability Issues: Difficult to manage for large, complex programs.
2. Low Security: Global variables can be accessed and modified from anywhere,
increasing the risk of errors.
3. Reduced Modularity: Functions and data are separate, making the program less
modular and harder to debug or update.

Example of POP in C:
#include <stdio.h>

// Function to calculate the sum of two numbers


int add(int a, int b) {
return a + b;
}
int main() {
int num1 = 10, num2 = 20;
int result = add(num1, num2);
printf("The sum is: %d\n", result);
return 0;
}
In this example, the program is divided into functions, and the flow is controlled by calling
these functions in sequence

Object-Oriented Programming (OOP)


Object-Oriented Programming (OOP) is a programming style that organizes software
design around data, or objects, rather than functions and logic. Key OOP concepts include
classes, objects, inheritance, encapsulation, and polymorphism.

OOP Concepts
1. Class 8. Destructors
2. Objects 9. Message Passing
3. Encapsulation 10. Dynamic Binding
4. Abstraction 11. Association
5. Polymorphism 12. Modularity
6. Inheritance 13. Composition
7. Constructors

1. Encapsulation
• Definition: Encapsulation is bundling data (attributes) and methods (functions) into
a single unit, usually a class, and restricting access to some components.
• Purpose: It ensures controlled access to an object's data using access modifiers
like private, protected, and public.

• Example:
class BankAccount:
def __init__(self, balance):
self.__balance = balance # Private attribute

def deposit(self, amount):


self.__balance += amount

def get_balance(self):
return self.__balance
Here, __balance is hidden and only accessible through the get_balance() method.

2. Abstraction
• Definition: Abstraction focuses on exposing only the essential features of an object
while hiding implementation details.
• Purpose: Simplifies complexity by showing only relevant details and reduces code
dependencies.

• Example:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass

class Circle(Shape):
def __init__(self, radius):
self.radius = radius

def area(self):
return 3.14 * self.radius ** 2

The Shape class abstracts the concept of area computation, and the Circle class
implements the details.

3. Inheritance
• Definition: Inheritance allows one class (child/subclass) to inherit properties and
methods from another class (parent/superclass).
• Purpose: Promotes code reuse and establishes a hierarchical relationship between
classes.

• Example:
class Vehicle:
def start(self):
print("Vehicle started")
class Car(Vehicle):
def drive(self):
print("Car is driving")

my_car = Car()
my_car.start() # Inherited method
my_car.drive()

The Car class inherits the start() method from the Vehicle class.

4. Polymorphism
• Definition: Polymorphism means "many forms." It allows objects to be treated as
instances of their parent class, with the ability to override methods for specific
behavior.
• Purpose: Promotes flexibility and enables the same interface to handle different
data types or classes.

• Example:
class Bird:
def sound(self):
print("Bird makes a sound")

class Sparrow(Bird):
def sound(self):
print("Sparrow chirps")

class Eagle(Bird):
def sound(self):
print("Eagle screeches")

def make_sound(bird):
bird.sound()

make_sound(Sparrow()) # Output: Sparrow chirps


make_sound(Eagle()) # Output: Eagle screeches
Here, different subclasses define their unique implementation of the sound() method.

5. Classes and Objects


• Definition:
o A class is a blueprint for creating objects, defining their structure and
behavior.
• An object is an instance of a class, containing real-world entities.
• Diagram: Class and Object

Example:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

def introduce(self):
print(f"My name is {self.name} and I am {self.age} years
old.")

john = Person("John", 30)


john.introduce()
6. Association
• Definition: Association represents a relationship between objects where one object
uses or interacts with another.
• Types:
o Aggregation: A "has-a" relationship where the child object can exist
independently of the parent.
o Composition: A "part-of" relationship where the child object depends on the
parent for its existence.

• Example:
class Engine:
def start(self):
print("Engine started")

class Car:
def __init__(self, engine):
self.engine = engine # Aggregation

def start_car(self):
self.engine.start()

engine = Engine()
my_car = Car(engine)
my_car.start_car()

7. Message Passing
• Definition: Objects communicate with each other by sending and receiving
information (messages) via method calls.
• Example:
class Calculator:
def add(self, x, y):
return x + y

calc = Calculator()
result = calc.add(5, 3) # Message sent to the object
print(result)

8. Dynamic Binding
• Definition: The process where a method call is resolved at runtime, enabling
polymorphism.
• Example:
class Animal:
def sound(self):
print("Some generic animal sound")

class Dog(Animal):
def sound(self):
print("Bark")

def make_sound(animal):
animal.sound() # Resolved at runtime

make_sound(Dog()) # Output: Bark

9. Modularity
• Definition: Breaking a program into smaller, self-contained units (classes and
objects) to promote reusability and maintainability.
• Example: Dividing a program into separate modules like User, Product, and Order.

Procedural-Oriented Object-Oriented Programming


Aspect
Programming (POP) (OOP)
Procedural paradigm (focuses Object-oriented paradigm
Paradigm
on procedures and functions). (focuses on objects).
Functions (procedures) that Objects that encapsulate data
Main Focus
operate on data. and behavior.
Organized into functions and Organized into classes and
Code Structure
procedures. objects.
Data is often global or shared, Data is encapsulated within
Data Handling
increasing risk of modification. objects and is more secure.
Limited; functions need to be Promotes reusability through
Reusability
manually reused or rewritten. inheritance and polymorphism.
Problem-Solving Step-by-step, breaking problems Models real-world entities as
Approach into functions. objects.
Less scalable; managing large Highly scalable; modular design
Scalability
programs is complex. makes maintenance easier.
High, as data is protected
Security Low, as data is not protected.
through encapsulation.
Examples C, COBOL, Fortran. Java, Python, C++, Dart.
This concise comparison highlights the key distinctions between POP and OOP in terms of
their design and usage.

Example to demonstrate all oop features:::

from abc import ABC, abstractmethod # For Abstraction

# Module 1: Account (Base and Abstract Classes)


class Account(ABC):
def __init__(self, account_holder, balance=0):
self._account_holder = account_holder # Encapsulation: Protected
Attribute
self._balance = balance # Encapsulation: Protected Attribute

@abstractmethod
def deposit(self, amount):
pass

@abstractmethod
def withdraw(self, amount):
pass

def get_balance(self): # Encapsulation: Controlled Access to Data


return self._balance

# Module 2: Account Types (Inheritance and Specific Behavior)


class SavingsAccount(Account):
def __init__(self, account_holder, balance=0, interest_rate=0.02):
super().__init__(account_holder, balance)
self.__interest_rate = interest_rate # Encapsulation: Private Attribute

def deposit(self, amount):


if amount > 0:
self._balance += amount
print(f"Deposited {amount} to Savings Account.")
else:
print("Deposit amount must be positive.")

def withdraw(self, amount):


if 0 < amount <= self._balance:
self._balance -= amount
print(f"Withdrew {amount} from Savings Account.")
else:
print("Insufficient balance or invalid amount.")

def calculate_interest(self):
return self._balance * self.__interest_rate
class CurrentAccount(Account):
def deposit(self, amount):
if amount > 0:
self._balance += amount
print(f"Deposited {amount} to Current Account.")
else:
print("Deposit amount must be positive.")

def withdraw(self, amount):


if amount > 0:
self._balance -= amount
print(f"Withdrew {amount} from Current Account.")
else:
print("Invalid withdrawal amount.")

# Module 3: Bank System (Composition and Modularity)


class BankSystem:
def __init__(self, name):
self.name = name
self.accounts = [] # Composition: Bank contains multiple accounts

def add_account(self, account):


self.accounts.append(account)
print(f"Account for {account._account_holder} added to {self.name}.")

def display_all_accounts(self):
print(f"\nAccounts in {self.name}:")
for account in self.accounts:
self.account_summary(account)

# Polymorphism
@staticmethod
def account_summary(account):
print(f"Account Holder: {account._account_holder}")
print(f"Balance: {account.get_balance()}")
if isinstance(account, SavingsAccount):
print(f"Interest: {account.calculate_interest()}")
print("-----")
# Main Program: Demonstrates All OOP Features, Including Composition and
Modularity
if __name__ == "__main__":
# Modularity: Organized into multiple modules for clarity and reuse
# Creating Accounts
savings = SavingsAccount("Alice", balance=1000)
current = CurrentAccount("Bob", balance=500)

# Composition: Bank contains accounts


bank = BankSystem("ABC Bank")
bank.add_account(savings)
bank.add_account(current)

# Operations on Accounts
savings.deposit(500)
savings.withdraw(300)
current.deposit(200)
current.withdraw(700)

# Displaying All Accounts (Polymorphism + Composition)


bank.display_all_accounts()

Real-Life Examples::
Encapsulation
1. Car Mechanism
• Encapsulation Concept: A car encapsulates complex mechanisms like the engine,
transmission, and braking systems.
• Real-Life Parallel: As a driver, you only interact with interfaces like the steering
wheel, pedals, and gear shifter without worrying about how the engine or brakes
work internally.
• In OOP Terms: The internal details of the car (engine mechanism) are private, and
you interact with it using public methods like accelerate(), brake(), and
changeGear().
2. Bank Account
• Encapsulation Concept: A bank account class may have private attributes like
account balance and account number.
• Real-Life Parallel: Customers can deposit, withdraw, or check the balance, but
they cannot directly manipulate the account balance.
• In OOP Terms: The attributes accountNumber and balance are private, and the
methods deposit(amount) and withdraw(amount) provide controlled access.
3. ATMs
• Encapsulation Concept: ATMs encapsulate functionality like cash withdrawal,
account inquiry, and password verification.
• Real-Life Parallel: You only interact with the ATM screen and keypad. You don't see
how the backend processes your card and PIN or connects to the bank's servers.
• In OOP Terms: The backend processes are private, while public methods are
provided for user interaction, such as enterPIN() or selectTransaction().
4. Smartphones
• Encapsulation Concept: Smartphones encapsulate functionalities like calling,
messaging, and internet browsing.
• Real-Life Parallel: As a user, you only use the apps (interfaces) and don't worry
about how the operating system or the hardware handles these operations.
• In OOP Terms: The hardware interactions are hidden (private), while apps provide
user-friendly public interfaces.
5. Online Shopping Systems
• Encapsulation Concept: E-commerce platforms encapsulate product catalogs,
payment processing, and order tracking.
• Real-Life Parallel: Customers can browse products, add items to the cart, and
make payments without knowing how inventory systems, payment gateways, or
logistics work.
• In OOP Terms: Attributes like product details and order status are private, and
public methods like addToCart(), checkout(), and trackOrder() allow controlled
interactions.
6. Healthcare Systems
• Encapsulation Concept: Patient data management systems encapsulate sensitive
information and provide restricted access.
• Real-Life Parallel: Doctors and staff can access patient records through authorized
systems, but not all hospital employees can see all details.
• In OOP Terms: Patient data is private, with controlled access provided through
secure methods like getPatientHistory().
7. Music Players
• Encapsulation Concept: A music player application encapsulates functionalities
like playing songs, adjusting volume, and creating playlists.
• Real-Life Parallel: Users interact with a simple interface, while the app handles
decoding and playing the audio files.
• In OOP Terms: Attributes like currentSong and volumeLevel are private, with public
methods like play(), pause(), and setVolume().

Abstraction
• A remote control for a television. The user interacts with buttons without needing to
understand the TV's internal workings.
• A smartphone interface where the user can use apps without knowing how the
software and hardware interact behind the scenes.
• A ride-sharing app where users book rides through an interface without
understanding the algorithm behind route optimization.
Inheritance
• A class Vehicle (base class) and subclasses like Car, Bike, and Truck that inherit
common properties (like wheels and fuel type) from Vehicle.
• A Person class that serves as a base class, with subclasses such as Employee,
Student, and Customer, which inherit common attributes like name and age while
adding specific properties.
• A Shape class as a base class with subclasses like Rectangle, Circle, and Triangle,
which have specific area calculation methods.

Polymorphism
• A function draw() that works for different shapes, such as Circles, Squares, and
Triangles, allowing the same method to operate on different object types.
• A payment() method that can process payments differently depending on whether
the payment type is a credit card, debit card, or digital wallet.
• A speak() method for different animal classes, such as Dog and Cat, where each class
implements the procedure to output the respective sound.
Constructor and Destructor
• A Game class where a constructor initializes the game state and a destructor
releases resources or saves the game when the player quits.
• An online shopping cart system where a constructor initializes a cart for users when
they log in, and a destructor clears the cart when the session ends.
• A ShoppingCart class that initializes with items when the user adds products and
clears the cart when the user completes the purchase.

Composition
• A Library that contains instances of Book and Member classes, where a library is
composed of books and members.
• A Computer class that includes CPU, RAM, and Storage components.
• A House consists of Room, Kitchen, and Bathroom classes, whereas a house
comprises multiple rooms.

Classes and Objects


• A Dog class representing the characteristics and behaviors of dogs, and objects like
dog1 and dog2 representing specific instances of the Dog class.
• A Plant class with attributes like species, height, and color, and objects like rose,
tulip, and sunflower represent specific plant types.
• A Book class with attributes like title, author, and ISBN, and objects representing
individual books in a library.

implementation of each of these OOP concepts using basic Python code:

1. Encapsulation
Encapsulation involves keeping data safe within a class by using private variables and
providing controlled access via methods.
class CoffeeMachine:
def __init__(self):
self.__water_level = 100 # Private variable (indicated by
__)

def add_water(self, amount):


self.__water_level += amount

def make_coffee(self):
if self.__water_level >= 10:
self.__water_level -= 10
print("Coffee made!")
else:
print("Not enough water, please refill!")

machine = CoffeeMachine()
machine.make_coffee() # Output: Coffee made!
machine.add_water(20) # Adjust water level

2. Inheritance
Inheritance allows a class to inherit attributes and methods from another class. Below, Car
and Bike inherit common properties and methods from the Vehicle class.

class Vehicle:
def __init__(self, make, model):
self.make = make
self.model = model

def start_engine(self):
print("Engine started!")

class Car(Vehicle):
def __init__(self, make, model, doors):
super().__init__(make, model)
self.doors = doors

def car_info(self):
print(f"Car: {self.make} {self.model}, Doors: {self.doors}")
class Bike(Vehicle):
def bike_info(self):
print(f"Bike: {self.make} {self.model}")

car = Car("Toyota", "Corolla", 4)


car.start_engine() # Output: Engine started!
car.car_info() # Output: Car: Toyota Corolla, Doors: 4

bike = Bike("Yamaha", "MT-07")


bike.start_engine() # Output: Engine started!
bike.bike_info() # Output: Bike: Yamaha MT-07

3. Polymorphism
Polymorphism allows different classes to use the same method name but with different
implementations.

class TV:
def power(self):
print("TV is now ON")

class Radio:
def power(self):
print("Radio is now ON")

# Using polymorphism
for device in [TV(), Radio()]:
device.power() # Output: "TV is now ON" then "Radio is now ON"

4. Abstraction
Abstraction hides complex details and only shows the essential parts. Below, Shape is an
abstract class with a method area() that its subclasses must implement.

from abc import ABC, abstractmethod

class Shape(ABC):
@abstractmethod
def area(self):
pass

class Circle(Shape):
def __init__(self, radius):
self.radius = radius

def area(self):
return 3.14 * self.radius * self.radius

class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height

def area(self):
return self.width * self.height

circle = Circle(5)
print("Circle area:", circle.area()) # Output: Circle area: 78.5

rectangle = Rectangle(4, 5)
print("Rectangle area:", rectangle.area()) # Output: Rectangle area: 20

1.2 Class and Object, Constructor, Destructor in Python :::


• Class: A structure that defines attributes and methods.
• Object: An instance of a class.
• Constructor: __init__() method in Python; automatically called when a new object is
created.
• Destructor: __del__() method; called when an object is destroyed (not commonly
needed in Python).
Example: Constructor and Destructor
class Person:
def __init__(self, name):
self.name = name
print(f"{self.name} is created.")

def __del__(self):
print(f"{self.name} is deleted.")
# Creating an object of the Person class
person1 = Person("Alice")
person2 = Person("Bob")
person3 = Person("John")
person4 = Person("Myra")
person5 = Person("Myra")
1.3 Types of Variables, Types of Methods
(Instance & Static)

Types of Variables in Python Oops

inside class
variables Outside class
vaiables / global
methods

Local class variales/ Instance


variables static variables variables

Public Private Protected


variables variables variables

Instance Variable: Specific to each object; accessed using self.


• Class Variable: Shared across all instances of the class.
Example: Instance and Class Variables
class School:
school_name = "XYZ School" # Class Variable

def __init__(self, student_name):


self.student_name = student_name # Instance Variable

student1 = School("John")
print(student1.student_name) # Output: John
print(School.school_name) # Output: XYZ School

Python's Object-Oriented Programming (OOP) categorizes variables into three types


based on their scope and usage: Instance Variables, Class Variables (Static
Variables), and Local Variables. Here's a detailed explanation:

1. Instance Variables
• Definition: Variables that are unique to each instance (object) of a class.
• Scope: Defined within methods (typically __init__) and prefixed with self to associate
them with an instance.
• Usage: Store data unique to each object.
• Access: Accessed and modified using the self keyword.
Example:

class Car:
def __init__(self, make, model):
self.make = make # Instance variable
self.model = model # Instance variable

# Creating objects
car1 = Car("Toyota", "Corolla")
car2 = Car("Honda", "Civic")

print(car1.make) # Output: Toyota


print(car2.model) # Output: Civic

2. Class Variables (Static Variables)


• Definition: Variables shared across all instances of a class.
• Scope: Defined within the class but outside any instance methods, prefixed with the
class name or cls in class methods.
• Usage: Store data common to all objects of a class.
• Access: Accessed using the class name (ClassName.variable) or cls in class
methods.
Example:
python
Copy code
class Car:
wheels = 4 # Class variable (shared by all instances)

def __init__(self, make, model):


self.make = make
self.model = model

# Creating objects
car1 = Car("Toyota", "Corolla")
car2 = Car("Honda", "Civic")

print(car1.wheels) # Output: 4
print(car2.wheels) # Output: 4
# Modify the class variable
Car.wheels = 3
print(car1.wheels) # Output: 3
print(car2.wheels) # Output: 3

3. Local Variables
• Definition: Variables declared within a method and accessible only inside that
method.
• Scope: Exists only during the method's execution and is destroyed afterward.
• Usage: Used for temporary operations within a method.
Example:
python
Copy code
class Car:
def display_info(self):
message = "This is a local variable" # Local variable
print(message)

# Creating an object
car = Car()
car.display_info() # Output: This is a local variable

# Uncommenting the next line will result in an error:


# print(message) # NameError: name 'message' is not defined

Summary Table:

Variable Defined In Scope Shared Access Method


Type Across
Objects?
Instance Inside Specific to No self.variable_name
Variables methods each object
(using self)
Class Directly Shared by Yes ClassName.variable_name
Variables inside the all objects or cls
class
Local Inside Within the No Only accessible inside the
Variables methods method method
(without self) only

Types of instance variables:


In Python, private, public, and protected members refer to the access control levels
of variables and methods within a class. While Python doesn't enforce strict access
modifiers like some other languages (e.g., Java or C++), it provides conventions to indicate
the intended accessibility of members.

1. Public Members
• Definition: Members (variables or methods) accessible from anywhere, both
inside and outside the class.
• Convention: Declared without any special prefix.
• Usage: For attributes and methods meant to be freely accessible.
Example:

class Example:
def __init__(self):
self.public_var = "I am Public" # Public variable

def public_method(self):
print("This is a public method.")

# Accessing public members


obj = Example()
print(obj.public_var) # Output: I am Public
obj.public_method() # Output: This is a public method.

2. Protected Members
• Definition: Members intended to be accessible within the class and its subclasses.
• Convention: Prefixed with a single underscore (_).
• Enforcement: This is a convention, not strict enforcement. The member can still be
accessed from outside the class but is marked as "for internal use."
Example:

class Parent:
def __init__(self):
self._protected_var = "I am Protected" # Protected variable

def _protected_method(self):
print("This is a protected method.")

class Child(Parent):
def access_protected(self):
print(self._protected_var) # Accessing protected member in subclass
self._protected_method()

# Accessing protected members


obj = Child()
obj.access_protected() # Output: I am Protected, This is a protected method.

# Technically accessible from outside, but discouraged


print(obj._protected_var) # Output: I am Protected

3. Private Members
• Definition: Members meant to be inaccessible directly from outside the class.
• Convention: Prefixed with a double underscore (__).
• Enforcement: Python uses name mangling to make it harder (not impossible) to
access private members from outside the class. The variable's actual name is
modified internally to include the class name.
Example:

class Example:
def __init__(self):
self.__private_var = "I am Private" # Private variable

def __private_method(self):
print("This is a private method.")

def access_private(self):
print(self.__private_var) # Accessing private member
self.__private_method()

# Accessing private members


obj = Example()
obj.access_private()
# Output:
# I am Private
# This is a private method.

# Attempting direct access (will raise AttributeError)


# print(obj.__private_var) # AttributeError

# Accessing via name mangling (not recommended)


print(obj._Example__private_var) # Output: I am Private
Summary Table:
Access
Syntax Access Scope
Modifier
variable / Accessible from anywhere (inside or
Public
method outside the class).
_variable / Accessible within the class and its
Protected
_method subclasses; technically accessible outside.
__variable / Accessible only within the class (via name
Private
__method mangling for external access).

Key Notes:
1. Name Mangling: Python changes private variables like __private_var to
_ClassName__private_var internally to make accidental access difficult.
2. Why the Flexibility? Python trusts the developer to follow conventions rather than
enforce strict rules.
3. Best Practices:
o Use public for general-purpose members.
o Use protected for members that subclasses need.
o Use private for sensitive data or methods you want to hide from external
access.
Types of methods in oops in python

Types Of Methods in Python


Oops

inside class Methods Outside Class


Methods
/ global methods

Local class methods / Instance


methods static methods methods

Public Private Protected


methods methods methods

• Instance Method: Operates on instance variables; needs self. Method Scope is


same as that of varables.
• Static Method: Does not need self to call it; uses @staticmethod decorator.
Example: Instance and Static Methods
class Calculator:
def add(self, x, y): # Instance Method
return x + y

@staticmethod
def subtract(x, y): # Static Method
return x - y

calc = Calculator()
print(calc.add(5, 3)) # Output: 8
print(Calculator.subtract(5, 3)) # Output: 2

Data Structures
Definition (D):
A Data Structure is a specific way of organizing, managing, and storing data in
a computer to be accessed and modified efficiently.

Definition:
A Data Structure is a tuple (D,F, A) where:
• D represents the data: the collection of values or elements to be stored and
manipulated.
• F represents the functions: the set of operations or methods performed on the data
(e.g., insert, delete, search, sort).
• A represents the axioms: the rules, properties, or constraints governing the structure
and behavior of the data.
This formal definition encapsulates the essence of data structures, emphasizing the
integration of data, functionality, and governing rules.

Elaborating Different Data Structures Using (D, F, A):

1. Built-in Data Structures:

a) List:
• D: A sequence of elements stored in a linear order (e.g., [1, 2, 3, 4]).
• F:
o Access elements by index: list[index].
o Add elements: append(value), insert(index, value).
o Remove elements: pop(index), remove(value).
o Sort elements: sort(), reverse().
• A:
o Elements are stored in contiguous memory locations.
o Allows duplicates and mixed data types (e.g., [1, "hello", 3.14]).
o Maintains insertion order.
b) Tuple:
• D: An immutable sequence of elements (e.g., (1, 2, 3)).
• F:
o Access elements: tuple[index].
o Operations like slicing and iteration.
o Methods: count(value), index(value).
• A:
o Immutable (cannot change elements after creation).
o Supports heterogeneous data types.
c) Set:
• D: An unordered collection of unique elements (e.g., {1, 2, 3}).
• F:
o Add elements: add(value), update(values).
o Remove elements: discard(value), remove(value).
o Set operations: union(), intersection(), difference().
• A:
o No duplicate elements allowed.
o Unordered (no indexing).
d) Dictionary (dict):
• D: A collection of key-value pairs (e.g., {"key1": "value1", "key2": "value2"}).
• F:
o Add/update key-value pairs: dict[key] = value.
o Access value by key: dict[key].
o Remove pairs: pop(key), clear().
• A:
o Keys must be unique.
o Keys are immutable (e.g., strings, numbers, tuples).

2. User-Defined Data Structures:


a) Arrays:
• D: A collection of elements of the same data type stored in contiguous memory
locations.
• F:
o Access by index: array[index].
o Modify elements: array[index] = value.
o Iterate and perform operations.
• A:
o Fixed size.
o Homogeneous data types.
b) Linked List:
• D: A sequence of nodes where each node contains data and a pointer to the next
node.
• F:
o Add nodes: append(value), insert(position, value).
o Delete nodes: remove(value).
o Traverse nodes.
• A:
o Dynamic memory allocation.
o Sequential access (no indexing).
c) Queues:
• D: A linear structure following the FIFO (First-In-First-Out) principle.
• F:
o Add element: enqueue(value).
o Remove element: dequeue().
o Peek: front() or rear().
• A:
o Elements are added at one end (rear) and removed from the other (front).
d) Stacks:
• D: A linear structure following the LIFO (Last-In-First-Out) principle.
• F:
o Add element: push(value).
o Remove element: pop().
o Peek: top().
• A:
o Elements are added and removed from the same end.
e) Trees:
• D: A hierarchical structure with nodes connected by edges (e.g., binary tree, AVL
tree).
• F:
o Traverse: in-order, pre-order, post-order.
o Add/Delete nodes.
o Search for elements.
• A:
o One root node, and each node has one parent (except root).
o Nodes can have multiple children.
f) Graphs:
• D: A collection of vertices (nodes) and edges connecting them.
• F:
o Add/Delete vertices and edges.
o Traverse: BFS, DFS.
o Shortest path algorithms: Dijkstra's, A*.
• A:
o Can be directed or undirected.
o Can be weighted or unweighted.

f) File :
• D: Data
Stores raw or structured data (e.g., text, binary, JSON, CSV).
• F: Functions
Basic Operations: Create, Read, Write, Delete.
Advanced Operations: Append, Search, Lock, Compress.
• A: Axioms
Follows rules like format (text, binary, structured), access type (sequential or
random), and metadata constraints.

Key Insights:
Each data structure can be systematically analyzed using this tuple-based formalism. The
combination of DDD, FFF, and AAA highlights:
• The data stored.
• The functions available for manipulation.
• The axioms defining behavior and constraints.

1.4 Types of Data Structures –


Data structures organize and store data efficiently. They are divided into two
main types:
• Linear Data Structures: Elements are arranged sequentially. Examples
include arrays, linked lists, stacks, and queues.
• Non-Linear Data Structures: Elements are arranged hierarchically.
Examples include trees and graphs.
Diagram: Linear vs. Non-Linear Structures

Types Of Data
Structures in Python
Built-in Data User Defined
Structures Data Structures
list set Linear Data Non-Linear Data
tuple dict Structures Structures

Array Linked Queue Stack Tree Graph File


List

• Methods1. Built-in Data Structures


Python's standard library provides these and is easy to use.
a. List
• Definition: Ordered, mutable, and allows duplicate elements.
• Example:

my_list = [10, 20, 30, 40]


my_list.append(50) # Adding an element
print(my_list) # Output: [10, 20, 30, 40, 50]

b. Set
• Definition: Unordered, mutable, and does not allow duplicate elements.
• Example:

my_set = {10, 20, 30, 30}


print(my_set) # Output: {10, 20, 30}
my_set.add(40)
print(my_set) # Output: {10, 20, 30, 40}

c. Tuple
• Definition: Ordered, immutable, and allows duplicate elements.
• Example:

my_tuple = (10, 20, 30)


print(my_tuple[1]) # Output: 20

d. Dictionary (dict)
• Definition: Mutable and stores key-value pairs.
• Example:

my_dict = {"name": "Alice", "age": 25}


print(my_dict["name"]) # Output: Alice
my_dict["age"] = 26
print(my_dict) # Output: {'name': 'Alice', 'age': 26}

2. User-Defined Data Structures


These require explicit implementation by the programmer.

a. Linear Data Structures


1. Arrays:
o Definition: Contiguous memory blocks storing elements of the
same type.
o Example (using array module):

from array import array


arr = array('i', [1, 2, 3, 4])
arr.append(5)
print(arr) # Output: array('i', [1, 2, 3, 4, 5])

2. Linked Lists:
o Definition: Consists of nodes, where each node contains data and
a reference to the next node.
o Example:

class Node:
def __init__(self, data):
self.data = data
self.next = None

class LinkedList:
def __init__(self):
self.head = None

def append(self, data):


new_node = Node(data)
if not self.head:
self.head = new_node
return
temp = self.head
while temp.next:
temp = temp.next
temp.next = new_node

def display(self):
temp = self.head
while temp:
print(temp.data, end=" -> ")
temp = temp.next
print(None)

ll = LinkedList()
ll.append(10)
ll.append(20)
ll.append(30)
ll.display() # Output: 10 -> 20 -> 30 -> None

3. Queues:
o Definition: Follows FIFO (First-In-First-Out) principle.
o Example (using queue module):

from queue import Queue


q = Queue()
q.put(10)
q.put(20)
q.put(30)
print(q.get()) # Output: 10

b. Non-Linear Data Structures


1. Trees:
o Definition: Hierarchical structure where each node has a parent
and child nodes.
o Example:

class TreeNode:
def __init__(self, data):
self.data = data
self.children = []

def add_child(self, child):


self.children.append(child)
def display(self):
print(self.data)
for child in self.children:
child.display()

root = TreeNode("Root")
child1 = TreeNode("Child 1")
child2 = TreeNode("Child 2")

root.add_child(child1)
root.add_child(child2)
root.display()
# Output:
# Root
# Child 1
# Child 2

2. Graph:
o Definition: Consists of nodes (vertices) connected by edges.
o Example:

graph = {
"A": ["B", "C"],
"B": ["A", "D", "E"],
"C": ["A", "F"],
"D": ["B"],
"E": ["B", "F"],
"F": ["C", "E"]
}
print(graph["A"])

# Output: ['B', 'C']

1.5 Key Data Structures in Python – List, Tuples, Set, Dictionaries


1. List: Ordered and mutable collection of items. Can hold multiple data
types.
o Example: my_list = [1, 2, 3, "apple"]
o Lists allow indexing, slicing, and modification.

my_list = [1, 2, 3]
my_list.append(4) # Adds 4 to the list
print(my_list) # Output: [1, 2, 3, 4]

2. Tuple: Ordered but immutable collection. Once created, elements


cannot be changed.
o Example: my_tuple = (1, 2, "banana")

my_tuple = (1, 2, 3)
print(my_tuple[0]) # Output: 1

3. Set: Unordered collection of unique items.


o Example: my_set = {1, 2, 3, "apple"}
o Sets are useful for operations like union, intersection, and
difference.

my_set = {1, 2, 3}
my_set.add(4)
print(my_set) # Output: {1, 2, 3, 4}

4. Dictionary: Unordered collection of key-value pairs. Each key is unique


and can be used to retrieve the value associated with it.
o Example: my_dict = {"name": "Alice", "age": 25}

my_dict = {"name": "Alice", "age": 25}


print(my_dict["name"]) # Output: Alice

Diagram: Dictionary Structure


Dictionary

-----------
| Key | Value |
-----------
| "name" | Alice |
| "age" | 25 |
-----------

Question Bank for Chapter 1: Introduction to OOP


Concepts & Data Structures,
1/2 Mark Questions
1. Define Object-Oriented Programming (OOP). (CO1)
2. What is encapsulation in OOP? (CO1)
3. Give an example of polymorphism. (CO1)
4. What does inheritance allow in OOP? (CO1)
5. What is the purpose of a constructor in a class? (CO1)
6. Name two types of data structures. (CO2)
7. What is the difference between a class and an object? (CO1)
8. What are instance methods? (CO1)
9. Explain the term “abstraction” in the context of OOP. (CO1)
10. What is a data structure? (CO2)
3.5 Marks Questions / 5 Marks Questions
1. Explain the concept of encapsulation with a real-life example. (CO1)
2. Describe how inheritance promotes code reusability in OOP with an
example. (CO1)
3. What are the advantages of using OOP over procedural programming?
(CO1)
4. Write a short Python code snippet to demonstrate how encapsulation is
implemented. (CO4)
5. Describe the role of constructors and destructors in a class. (CO1)
6. Differentiate between linear and non-linear data structures with
examples. (CO2)
7. Explain polymorphism and provide a simple code example illustrating
this concept. (CO1)
8. Explain in detail all types of data structures.
9. Explain the types of variables in OOP-python
10. Explain the types of methods/functions in OOP-python.
7 Marks Questions
1. Explain in detail all types of data structures.
2. Discuss the four main principles of OOP. Provide examples to illustrate
each principle. (CO1)
3. Explain the difference between instance variables and class variables
with examples. (CO1)
4. Write a Python program to demonstrate encapsulation, inheritance, and
polymorphism in a single example. (CO4)
5. Describe the key data structures in Python (list, tuples, sets, dictionaries)
and their use cases. (CO2)
6. Compare and contrast arrays and linked lists regarding their structure,
advantages, and disadvantages. (CO2)
14 Marks Questions
1. Explain all concepts of OOP with definitions, concepts, real-life
examples, diagrams, and Python code examples.
2. Discuss the importance of OOP in software development. How do
encapsulation, inheritance, and polymorphism contribute to creating
modular and maintainable code? Provide relevant examples. (CO1, CO4)
3. Explain the concepts of abstraction and encapsulation in detail and
describe how they can be implemented in Python with suitable
examples. (CO1, CO4)
4. Create a comprehensive example involving a class hierarchy where you
use inheritance, demonstrate polymorphism, and implement
encapsulation. Explain your design choices and the advantages of this
approach. (CO1, CO4)
5. Analyze the advantages and disadvantages of using various data
structures (arrays, linked lists, stacks, queues) in programming, focusing
on their performance in terms of time and space complexity. (CO2, CO4)
6. Discuss how OOP principles can be used to model real-world entities.
Please provide a detailed example incorporating all four OOP principles
and discuss its implementation in Python. (CO1, CO4)

You might also like