Unit – 1
Abstract Data Type
DATA STRUCTURES
DESIGN
2
INTRODUCTION TO DATA STRUCTURES
• Data structure is a branch of computer science. The study of data structure helps to understand
how data is organized and how data flow is managed to increase the efficiency of any process or
program.
• Data structure is the structural representation of logical relationship between data elements.
Definition
Data structure is a way of storing, organizing and retrieving data in a computer, so that it can be
used efficiently. It provides a way to manage large amount of data proficiently.
3
Need for Data Structures
 It gives different level of organization of data.
 It tells how data can be stored and accessed.
 It provides a means to manage large amount of data
efficiently.
 It provides fast searching and sorting of data.
Classification of Data structures
• Data structures can be classified into two categories.
i) Primitive Data structures
ii) Non-Primitive Data structures
4
Primitive Data Structures
• Primitive data structures are basic data structures. These can be manipulated or operated directly
by the machine level instructions. Basic data types such as integer, real, character and Boolean
come under this type. Example: int, char, float.
Non-Primitive Data Structures
 Non-primitive data structures are derived from primitive data structures.
 These data structures cannot be operated or manipulated directly by the machine level
instructions.
 They define the group of homogeneous and non-homogenous data items.
 Examples: Array, Lists, Graphs, Trees etc.
5
1. Linear Data Structures
 A data structure that maintains a linear relationship among the elements is called a linear data
structure.
 Here, the data are arranged in a sequential fashion. But in the memory the arrangement may not
be sequential.
 Examples: Arrays, linked lists, stack and queues.
2. Non-Linear Data Structures
 A data structure that maintains the data elements in hierarchical order are known as
nonlinear data structure. Thus, they are present at various levels.
 They are comparatively difficult to implement and understand as compared to the linear
data structures. Examples: Trees and Graphs.
6
3. Static Data Structures
• In static data structures the size of the structure is fixed.
• The content of the data structures can be modified without changing the memory space allocated
to it. Example: Array
4. Dynamic Data Structures
In dynamic data structures the size of the structure is not fixed and can be modified during the
operations performed on it.
• Dynamic data structures are designed to facilitate change of data structures in the run time.
Example: Linked list.
7
ABSTRACT DATA TYPES (ADTs)
• In the real-world, the programs evolve as a result of new requirements or constraints. So, a
modification to a program commonly requires a change in one or more of its data structures.
• For example, to add a new field to a student record, to keep track of more information about
each student, then it will be better to replace an array with a linked structure to improve the
program’s efficiency. In such a scenario, rewriting every procedure that uses the changed
structure is not desirable.
• Therefore, a better alternative is to separate the use of a data structure from the details of its
implementation. This is the principle underlying use of abstract data type.
8
• Definition
• An abstract data type or ADT is a mathematical abstraction. It specifies a set of operations (or
methods) and the semantics of the operations (what they do), but it does not specify the
implementation of the operations.
• Examples: List ADT, Stack ADT, Queue ADT, Trees, Graphs etc.
• The definition of ADT only mentions what operations are to be performed but not how these
operations will be implemented. It does not specify how data will be organized in memory and
what algorithms will be used for implementing the operations. It is called “abstract” because it
gives an implementation-independent view. The process of hiding the nonessential details and
providing only the essentials of problem solving is known as data abstraction.
9
• The set of operations can be grouped into four categories. They are,
• Constructors : Functions used to initialize new instances of the ADT at the time of
instantiation.
• Accessors : Functions used to access the data elements contained in an instance
without making any modification to it.
• Mutators : Functions that modify the data elements of an ADT instance.
• Iterators : Functions that enable sequential access of the data elements.
10
Advantages of using ADTs
• ADTs give the feel of plug and play interface. So it is easy for the programmer to implement ADT. For
example, to store collection of items, it can be easily put the items in a list. That is,
BirdsList=[‘Parrot’,’Dove’,’Duck’,’Cuckoo’]
• To find number of items in a list, the programmer can use len function without implementing the code.
• The ADTs reduces the program developing time. Because the programmer can use the predefined
functions rather than developing the logic and implementing the same.
• The usage of ADTs reduces the chance of logical errors in the code, as the usage of predefined functions
in the ADTs are already bug free.
• ADTs provide well defined interfaces for interacting with the implementing code.
• ADTs increase the understandability and modularity of the code.
11
ADTs AND CLASSES
• A data structure is the implementation for an ADT. In an object-oriented language, an ADT and its
implementation together make up a class. Each operation associated with the ADT is implemented by a member
function or method. The variables that define the space required by a data item are referred to as data members.
An object is an instance of a class that is created and takes up storage during the execution of a computer
program.
12
In this way, the user can use an abstract data type to define new class by specifying attributes and
operations.
13
INTRODUCTION TO OBJECT ORIENTED PROGRAMMING
Goals, Principles and Patterns
• The main ‘actors’ in the object-oriented paradigm are called objects. Each object is an instance of
a class.
• Each class presents to the outside world a concise and consistent view of the objects, that are
instances of this class, without going into too much unnecessary detail or giving others access to
the inner workings of the objects.
• The class definition typically specifies instance variables, also known as data members, that the
object contains, as well as the methods, also known as member functions, that the object can
execute.
• This view of computing is intended to fulfill several goals and incorporate several design
principles.
14
• Example 2:
• Consider a user defined Student class with
student_name, student_id and student_mark as its data
members along with operations get_name(),
put_name(), get_id(), put_id(), compute_marks() and
display_marks(_) as the member functions.
• This Student class would represent a composite type of
data, named Student, consisting of student_name (String
type), student_id (integer or string type) and student
mark (float type).
•
• Thus, an instance of this student class represents an
abstract view of the student details. The class Student
can be considered to represent a data type that is
abstract in nature. Thus, the classes are known to be
abstract data type (ADT).
15
Object-Oriented Design Goals
• Software implementations should achieve robustness, adaptability, and reusability.
Robustness
• Every good programmer wants to develop software that is correct, which means that a program produces the
right output for all the anticipated inputs in the program’s application. The software is said to be robust, if it is
capable of handling unexpected inputs that are not explicitly defined for its application. For example, if a
program is expecting a positive integer and instead is given a negative integer, then the program should be able
to recover gracefully from this error.
16
Adaptability
• Modern software applications, such as Web browsers and Internet search engines, involve large programs that
are used for many years. Software, therefore, needs to be able to evolve over time in response to changing
conditions in its environment. Thus, another important goal of quality software is that it achieves adaptability
(also called evolvability). Related to this concept is portability, which is the ability of software to run with
minimal change on different hardware and operating system platforms. An advantage of writing software in
Python is the portability provided by the language itself.
Reusability
• Going hand in hand with adaptability, the software be reusable. That is, the same code should be usable as a
component of different systems in various applications. Developing quality software is designed in a way that
makes it easily reusable in future applications. Such reuse should be done with care.
17
Object-Oriented Design Principles
The important principles in object-oriented approach, are as follows
• Modularity
 Abstraction
 Encapsulation
Modularity
• Modern software systems consist of several different components that must interact correctly in order for the entire
system to work properly. Keeping these interactions requires that these different components be well organized.
Modularity refers to an organizing principle in which different components of software system are divided into
separate functional units.
• Modularity in a software system can provide a powerful organizing framework that brings clarity to an
implementation. In Python, a module is a collection of closely related functions and classes that are defined together
in a single file of source code. For example, Python’s standard library math module, provides definitions for key
mathematical constants and functions, and the os module, provides support for interacting with the operating system.
• The uses of modularity:
• It increases the robustness of the program.
 It is easier to test and debug separate components of the program.
 It enables software reusability.
18
Abstraction
• Abstraction allows dealing with the complexity of the object. Abstraction allows picking out the relevant
details of the object, and ignoring the non-essential details.
• Applying the abstraction to the design of data structures gives rise to Abstract Data Types (ADTs). An ADT
is a mathematical model of a data structure that specifies the type of data stored, the operations supported
on them, and the types of parameters of the operations. An ADT specifies what each operation does, but not
how it does it.
• Python supports abstract data types using a mechanism known as an abstract base class (ABC). An abstract
base class cannot be instantiated (i.e., you cannot directly create an instance of that class), but it defines one
or more common methods that all implementations of the abstraction must have. An ABC is realized by one
or more concrete classes that inherit from the abstract base class while providing implementations for those
method declared by the ABC.
19
Encapsulation
• Encapsulation means information hiding. It hides the data defined in the class. Encapsulation separates
implementation of the class from its interface. The interaction with the class is through the interface provided
by the set of methods defined in the class. This separation of interface from its implementation allows changes
to be made in the class without affecting its interface.
• One of the advantages of encapsulation is that it gives freedom to the programmer to implement the details of
a component, without concern that other programmers will be writing the code that intricately depends on
those internal decisions. The only constraint on the programmer of a component is to maintain the public
interface for the component, as the other programmers will be writing the code that depends on that interface.
20
Object Oriented Design Patterns
• Object-oriented design facilitates reusable, robust, and adaptable software. Designing good code
requires the effective use of object-oriented design techniques.
• Computing researchers and practitioners have developed a variety of organizational concepts and
methodologies for designing quality object-oriented software that is concise, correct, and reusable.
• The concept of a design pattern, describes a solution to a “typical” software design problem. A
pattern provides a general template for a solution that can be applied in many different situations.
• It describes the main elements of a solution in an abstract way that can be specialized for a
specific problem at hand. The design pattern can be consistently applied to implementations of
data structures and algorithms.
• These design patterns fall into two groups patterns for solving algorithm design problems and
patterns for solving software engineering problems.
21
• The algorithm design patterns include the
following:
 Recursion
 Amortization
 Divide and conquer
 Prune and search
 Brute force
 Dynamic Programming
 The greedy method
Likewise, the software engineering design
patterns include:
 Iterator
 Adapter
 Position
 Composition
 Template method
 Locator
22
CLASSES IN PYTHON
• A class serves as the primary means for abstraction in object-oriented programming. In python everything is an
object. Everything is an instance of some class. A class also serves as a blueprint for its instances.
 The data values stored inside an object are called attributes. The state information for each instance is
represented in the form of attributes (also known as fields, instance variables, or data members).
 A class provides a set of behaviors in the form of member functions (also known as methods), with
implementations that are common to all instances of that class.
23
Defining a class
A class is the definition of data and methods for a specific type of object.
• Syntax:
class classname:
<statement1>
.
.
.
<statement>
The class definition begins with the keyword class, followed by the name of the class, a colon and an indented block of
code that serves as the body of the class.
The body includes definitions for all methods of the class. These methods are defined as functions, with a special
parameter, named self, that is used to identify the particular instance upon which a member is invoked.
When a class definition is entered, a new namespace is created, and used as the local scope. Thus, all assignments to
local variables go into this new namespace.
24
• Example:
class customer:
def _ _init_ _(self,name,iden,acno):
self.custName=name
self.custID=iden
self.custAccNo=acno
def display(self):
print("Customer Name = ",self.custName)
print("Customer ID = ",self.custID)
print("Customer Account Number = ",self.custAccNo)
c = customer("Ramesh",10046,327659)
c.display()
25
The Self Identifier and Self Parameter
• In python, the self-identifier places a key role. Self identifies the instance upon which a method
is invoked. While writing function in a class, at least one argument has to be passed, that is called
self-parameter. The self-parameter is a reference to the class itself and is used to access variables
that belongs to the class.
• In python programming self is a default variable that contains the memory address of the
instance of current class. So self is used to reuse all the instance variable and instance methods.
• Example: self.custName, self.custID, self.custAccNo
•
26
Object Creation
 An object is the runtime entity used to provide the functionality to the python class.
 The attributes defined inside the class are accessed only using objects of that class.
 The user defined functions also accessed by using the object.
 As soon as a class is created with attributes and methods, a new class object is created with the same name as the class.
 This class object permits to access the different attributes as well as to instantiate new objects of that class.
 Instance of the object is created using the name same as the class name and it is known as object instantiation.
 One can give any name to a newly created object.
Syntax:
object_name = class_name
The dot(.) operator is used to call the functions.
Syntax:
object_name . function_name()
27
Class variable and Instance variable
• Class variable is defined in the class and can be used by all the instances of that class.
 Instance variable is defined in a method and its scope is only with in the object that defines it.
 Every object of the class has its own copy of that variable. Any change made to the variable
don’t reflect in other objects of that class.
 Instance variables are unique for each instance, while class variables are shared by all instances.
28
• Example:
class Order:
def _ _init_ _(self, coffee_name, price):
self.coffee_name = coffee_name
self.price = price
ram_order = Order("Espresso", 210)
print(ram_order.coffee_name)
print(ram_order.price)
paul_order = Order("Latte", 275)
print(paul_order.coffee_name)
print(paul_order.price)
• In this example, coffee_name and price are the class
variables. ram_order and paul_order are the two
instances of this class. Each of these instances has
their own values set for
the coffee_name and price instance variables.
• When ram’s order details are printed in the console,
the values Espresso and 210 are returned. When
Paul’s order details are printed in the console, the
values Latte and 275 are returned.
• This shows that, instance variables can have
different values for each instance of the class,
whereas class variables are the same across all
instances.
29
A constructor is a special method used to create and initialize an object of a class.
This method is defined in the class.
The constructor is executed automatically at the time of object creation.
In python _ _init_ _() method is called as the constructor of the class. It is always
called when an object is created.
The primary responsibility of _ _init_ _ method is to establish the state of a
newly created object with appropriate instance variables.
Syntax:
def _ _init_ _(self):
#body of the constructor
Where,
def keyword is used to define function.
_ _init_ _() method: It is a reserved method. This method gets called as soon as
an object of a class is instantiated.
self: The first argument self refers to the current object. It binds the instance to
the _ _init_ _() method. It is usually named self to follow the naming convention.
Example:
class student:
def __init__(self,rollno,name,age):
self.rollno=rollno
self.name=name
self.age=age
print("student object is created")
s=student(1091,"Amala",21)
print("Roll no of the student=",s.rollno)
print("Name of the student=",s.name)
print("Age of the student=",s.age)
Output:
Student object is created
Roll no of the student=1091
Name of the student=Amala
Age of the student=21
Constructor
30
Types of constructors
• There are three types of constructors
1. Default Constructor
2. Non-Parameterized Constructor
3. Parameterized Constructor
 Python will provide a default constructor if no constructor is defined.
 Python adds a default constructor when the programmer does not include the constructor in the
class or forget to declare it.
 Default constructor does not perform any task but initializes the objects. It is an empty
constructor without a body.
31
Non-Parametrized Constructor
• A constructor without any arguments is called a non-parameterized constructor. This type of constructor is used to initialize each object with
default values.
 This constructor does not accept the arguments during object creation. Instead, it initializes every object with the same set of values.
Example:
class Employee:
def _ _init_ _(self):
self.name = "Ramesh"
self.EmpId = 100456
def display(self):
print("Employee Name = ", self.name, " nEmployee Id = ",self.EmpId)
emp = Employee()
emp.display()
Output:
Employee Name = Ramesh
Employee Id = 100456
32
Parameterized constructor
•Constructor with parameters is known as parameterized constructor.
•The first parameter to constructor is self that is a reference to the being constructed, and the rest of the arguments are
provided by the programmer. A parameterized constructor can have any number of arguments.
Example:
class Employee:
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary
def display(self):
print(self.name, self.age, self.salary)
# creating object of the Employee class
emp1 = Employee('Banu', 23, 17500)
emp1.display()
emp2 = Employee('Jack', 25, 18500)
emp2.display()
Output:
Banu 23 17500
Jack 25 18500
33
Destructor is a special method that is called when an object gets
destroyed.
A class can define a special method called destructor with the help of
__del()__. In Python, destructor is not called manually but completely
automatic, when the instance(object) is about to be destroyed.
It is mostly used to clean up non memory resources used by an
instance(object).
Example: For Destructor
class Student:
# constructor
def __init__(self, name):
print('Inside Constructor')
self.name = name
print('Object initialized')
def display(self):
print('Hello, my name is', self.name)
# destructor
def __del__(self):
print('Inside destructor')
print('Object destroyed')
# create object
s1 = Student('Raja')
s1.display()
# delete object
del s1
Output:
Inside Constructor
Object initialized
Hello, my name is Raja
Inside destructor
Object destroyed
Destructor
34
Iterators
 Iteration is an important concept in the design of data structures. An iterator is an object that contains a
countable number of elements that can be iterated upon.
 Iterators allows to traverse through all the elements of a collection and return one element at a time.
 An iterator object must implement two special methods, iter() and next() collectively called iterator
protocol.
 An object is called iterable if it gets an iterator from it. Most built-in containers in python are, list, tuple,
string etc.
 The _ _iter_ _() method returns the iterator object itself. If required, some initialization can be
performed.
 The _ _next_ _() method returns the next element of the collection. On reaching the end, it must raise
stop Iteration exception to indicate that there are no further elements.
35
class sequencegen:
def __init__(self,limit):
self.limit=limit
def __iter__(self):
self.x=1
return self
def __next__(self):
x=self.x
if x>self.limit:
raise StopIteration()
else:
self.x=x+1
return x
for i in sequencegen(5):
print(i)
Output:
1
2
3
4
5
36
• Encapsulation is one of the fundamental concepts
in object-oriented programming. Encapsulation in
Python describes the concept of bundling data and
methods within a single unit. A class is an example
of encapsulation as it binds all the data members (
instance variables) and methods into a single unit.
ENCAPSULATION
37
class Employee:
def __init__(self, name, salary, project):
# data members
self.name = name
self.salary = salary
self.project = project
# method to display employee's details
def display(self):
# accessing public data member
print("Name: ", self.name, 'Salary:', self.salary)
def work(self):
print(self.name, 'is working on', self.project)
# creating object of a class
emp = Employee('Jess', 40000, 'Infosys')
# calling public method of the class
emp.display()
emp.work()
Output:
Name: Jess Salary: 40000
Jess is working on Infosys
In this example, an Employee class defining employee attributes such as name, salary and project as an instance
variables and implementing its behavior using display() and work() instance methods.
• Encapsulation, hide an object’s internal representation from the outside. This is called information hiding.
• Encapsulation allows us to restrict accessing variables and methods directly and prevent accidental data
modification by creating private data members and methods within a class.
38
Data hiding using access modifiers
• Encapsulation can be achieved by declaring the data members and methods of a class either as private or
protected. But in Python, there is no direct access modifiers like public, private, and protected. This can be
achieved by using single underscore and double underscores. Single underscore represents the protected and
double underscore represents the private members.
39
Public data members are accessible within and outside of a
class. All member variables of the class are by default public.
Example:
class Employee:
# constructor
def __init__(self, name, salary):
# public data members
self.name = name
self.salary = salary
# public instance methods
def display(self):
# accessing public data member
print("Name: ", self.name, 'Salary:', self.salary)
# creating object of a class
emp = Employee('Jess', 40000)
# accessing public data members
print("Name: ", emp.name, 'Salary:', emp.salary)
# calling public method of the class
emp.display()
Output:
Name: Jess Salary: 40000
Name: Jess Salary: 40000
Public Member
40
The variables can be protected in the class by marking them
as private. To define a private member, prefix the variable
name with two underscores. Private members are accessible
only within the class.
Example: Access private member outside of a class using an
instance method.
class Employee:
# constructor
def __init__(self, name, salary):
# public data member
self.name = name
# private member
self.__salary = salary
# public instance methods
def display(self):
# private members are accessible from a class
print("Name: ", self.name, 'Salary:', self.__salary)
emp = Employee('Jess', 40000)
emp.display()
Output:
Name: Jess Salary: 40000
Private Member
41
Protected members are accessible within the class and also available to its
sub-classes. To define a protected member, prefix the member name with a
single underscore.
Protected data members are used in inheritance and to allow data members
access to only child classes.
Example: Protected member in inheritance.
class Company:
def _ _init_ _(self):
# Protected member
self._project = "Infosys"
class Employee(Company):
def _ _init_ _(self, name):
self.name = name
Company._ _init_ _(self)
def display(self):
print("Employee name :", self.name)
# Accessing protected member in child class
print("Working on project :", self._project)
c = Employee("Jess")
c.display()
# Direct access protected data member
print('Project:', c._project)
Output:
Employee name : Jess
Working on project : Infosys
Project: Infosys
Protected Member
42
Advantages of Encapsulation
1. The main advantage of using encapsulation is the security of the data. Encapsulation protects an
object from unauthorized access.
2. Encapsulation hide an object’s internal representation from the outside called data hiding.
3. It simplifies the maintenance of the application by keeping classes separated and preventing
them from tightly coupling with each other.
4. Bundling data and methods within a class makes code more readable and maintainable.
43
OPERATOR OVERLOADING
Operator overloading means giving extended meaning beyond their predefined operational meaning. For example, operator + is used to
add two integers as well as join two strings and merge two lists.
The same built-in operator or function shows different behavior for objects of different classes, this is called operator overloading.
Example:
# add 2 numbers
print(100 + 200)
# concatenate two strings
print('Python' + 'Programming')
# merger two list
print([10, 20, 30] + ['Data Structures', 'And', 'Algorithms'])
Output:
300
PythonProgramming
[10, 20, 30, 'Data Structures', 'And', 'Algorithms']
The operator + is used to carry out different operations for distinct data types. This is one of the simplest occurrences of polymorphism in
Python.
44
To perform operator overloading, python provides some special function or magic function that is automatically invoked when it is
associated with the particular object. If + operator is used, the magic method _add_ is automatically invoked.
Example:
class item:
def _ _init_ _(self, price):
self.price = price
# Overloading + operator with magic method
def _ _add_ _(self, other):
return self.price + other.price
b1 = item(400)
b2 = item(300)
print("Total Price: ", b1 + b2)
Output:
Total Price: 700
In this example, addition is implemented by a special method in python called the _add_ method. When two integers are added
together, this method is called to create a new integer object.
45
 Executing x+y, calls the int class _add_ method when x is an integer, but it calls the float types
_add_ method when x is float. The operand on the left-hand side determines which add method
is called. Thus the + operator is overloaded.
 When a binary operator is applied to two instances of different types, as in 5 * ‘Hello’, Python
gives deference to the class of the left operand.
 In this example, Python would effectively check if the int class provides a sufficient definition
for how to multiply an instance by a string, via the _ _mul_ _ method. If that class does not
implement such a behavior, Python checks the class definition for the right-hand operand, in the
form of a special method named _ _rmul_ _ (i.e., right multiply). This provides a way for a
new user-defined class to support mixed operations that involve an instance of an existing class.
46
INHERITANCE
• A natural way to organize various structural components of a software package is in a hierarchical fashion.
 A hierarchical design is useful in software development, as common functionality can be grouped at the most general level,
thereby promoting reuse of code, while differentiated behaviors can be viewed as extensions of the general case.
 In object-oriented programming the mechanism for a modular and hierarchical organization is a technique known as
inheritance. This allows a new class to be defined based upon an existing class as the starting point.
 In object-oriented programming, the existing class is typically described as the base class, parent class or super class, while the
newly defined class is known as the subclass or child class.
 There are two ways in which a subclass can differentiate itself from its superclass. A subclass may specialize an existing
behavior by providing a new implementation that overrides an existing method. A subclass may also extend its superclass by
providing brand new methods.
 Inheritance is a mechanism through which we can create a class or object based on another class or object. In other words, the
new objects will have all the features or attributes of the class or object on which they are based. It supports code reusability.
47
48
In Python, based upon the number of child and parent classes involved, there are five types of inheritance. The
types of inheritance are listed below:
i. Single inheritance
ii. Multiple Inheritance
iii. Multilevel inheritance
iv. Hierarchical Inheritance
v. Hybrid Inheritance
Single Inheritance
In single inheritance, a child class inherits from a single-parent class. Here is one child class and one parent class.
49
Example:
# Base class
class Vehicle:
def Vehicle_info(self):
print('Inside Vehicle class')
# Child class
class Car(Vehicle):
def car_info(self):
print('Inside Car class')
# Create object of Car
car = Car()
# access Vehicle's info using car object
car.Vehicle_info()
car.car_info()
Output:
Inside Vehicle class
Inside Car class
Here class car inherits from class Vehicle.
50
• In multiple inheritance, one child class can inherit from multiple
parent classes. So here is one child class and multiple parent classes.
# Parent class 1
class Person:
def person_info(self, name, age):
print('Inside Person class')
print('Name:', name, 'Age:', age)
# Parent class 2
class Company:
def company_info(self, company_name, location):
print('Inside Company class')
print('Name:', company_name, 'location:', location)
# Child class
class Employee(Person, Company):
def Employee_info(self, salary, skill):
print('Inside Employee class')
print('Salary:', salary, 'Skill:', skill)
# Create object of Employee
emp = Employee()
# access data
emp.person_info('Jessica', 28)
emp.company_info('YouTube', ' California ')
emp.Employee_info(12000, 'Cloud Computing')
Output:
Inside Person class
Name: Jessica Age: 28
Inside Company class
Name: YouTube location: California
Inside Employee class
Salary: 12000 Skill: Cloud Computing
Multiple Inheritance
51
52
• In multilevel inheritance, a class inherits from a child class or derived
class. Suppose three classes A, B, C. A is the superclass, B is the child
class of A, C is the child class of B. In other words, a chain of
classes is called multilevel inheritance.
# Base class
class Vehicle:
def Vehicle_info(self):
print('Inside Vehicle class')
# Child class
class Car(Vehicle):
def car_info(self):
print('Inside Car class')
# Child class
class SportsCar(Car):
def sports_car_info(self):
print('Inside SportsCar class')
# Create object of SportsCar
s_car = SportsCar()
# access Vehicle's and Car info using
SportsCar object
s_car.Vehicle_info()
s_car.car_info()
s_car.sports_car_info()
Output:
Inside Vehicle class
Inside Car class
Inside SportsCar class
Multilevel Inheritance
53
Hierarchical Inheritance
• In Hierarchical inheritance, more than one child class is derived from a single parent class. In other words, one parent
class and multiple child classes.
class Vehicle:
def info(self):
print("This is Vehicle")
class Car(Vehicle):
def car_info(self, name):
print("Car name is:", name)
class Truck(Vehicle):
def truck_info(self, name):
print("Truck name is:", name)
54
obj1 = Car()
obj1.info()
obj1.car_info('BMW')
obj2 = Truck()
obj2.info()
obj2.truck_info('Ford')
Output:
This is Vehicle
Car name is: BMW
This is Vehicle
Truck name is: Ford
•
55
• When inheritance consists of multiple types or a combination
of different inheritance then it is called hybrid inheritance.
class Vehicle:
def vehicle_info(self):
print("Inside Vehicle class")
class Car(Vehicle):
def car_info(self):
print("Inside Car class")
class Truck(Vehicle):
def truck_info(self):
print("Inside Truck class")
# Sports Car can inherits properties of Vehicle and Car
class SportsCar(Car, Vehicle):
def sports_car_info(self):
print("Inside SportsCar class")
# create object
s_car = SportsCar()
s_car.vehicle_info()
s_car.car_info()
s_car.sports_car_info()
Output:
Inside Vehicle class
Inside Car class
Inside SportsCar class
Hybrid Inheritance
56
Namespaces
 Whenever an identifier is assigned to a value, its definition is made with a specific scope. Top level
assignments are known as global scope. Assignments made with in the body of a function have local
scope to that function call.
 In Python, when computing a sum with the syntax x + y, the names x and y must have been previously
associated with objects that serve as values. The process of determining the value associated with an
identifier is known as name resolution.
 A namespace manages all of the identifiers that are defined in a particular scope, mapping each name to its
associated value. In Python, functions, classes and modules are class objects and so the value associated
with an identifier in a namespace may be a function, class or module.
 A namespace is a collection of currently defined symbolic names along with information about the object
that each name references. We can think of a namespace as a dictionary, in which the keys are the object
names and the values are the objects themselves. Each key-value pair maps a name to its corresponding
object.
57
Types of namespaces
i) Built-in Namespace
The built-in namespace contains the names of all of Python’s built-in objects. These are available at all times when Python is running.
The Python interpreter creates the built-in namespace when it starts up. This namespace remains in existence until the interpreter terminates.
Example:
Name=input("Enter your name:") #input() is built-in function
print(Name) #print() is built-in function
58
Global Namespace
•The global namespace contains any names defined at the level of the main program. Python creates the
global namespace when the main program body starts, and it remains in existence until the interpreter
terminates.
•The interpreter creates a global namespace for any module that the program loads with the import
statement.
Example:
x=10 # global scope of variable in python
def f1(): #function definition
print(x) #variable accessed inside the function
f1()
59
i) Local namespace
In Python, the interpreter creates a new namespace whenever a function executes. That namespace is local to
the function and remains in existence until the function terminates.
A local namespace can access global as well as built-in namespaces.
Example:
def f1(): #function definition
y=20 #Local scope of variable in python
print(y) #variable accessed inside the function
f1()
• The variable ‘y’ is declared in a local namespace and has a local scope of variable in python.
60
SHALLOW AND DEEP COPYING
• In some applications, it is necessary to subsequently modify either the original or copy in an independent
manner.
• Consider an application to manage various lists of colors. Each color is represented by an instance of a
presumed color class. warmtones is an identifier denote an existing list of such colors (e.g., oranges, browns).
• In this application, we wish to create a new list named palette, which is a copy of the warmtones list and
subsequently wanted to add additional colors to palette, or to modify or remove some of the existing
colors, without affecting the contents of warmtones.
• If we execute the command,
• palette = warmtones
• This creates an alias as shown in figure and no new list is created. Instead, the new identifier palette references
the original list. If we add or remove colors from palette, it will change the wormtones list also.
61
Shallow Copy
• In shallow copy, the new list is initialized so that its contents are precisely same as the original
sequence.
• If we execute the command,
palette = list (warmtones)
• It creates a new instance of the list. This is known as the shallow copy.
• The new list represents a sequence of references to the same elements as in the first. We can add
or remove elements from palette without affecting warmtones.
• However, if we edit a color instance from the palette list, we effectively change the contents of
warmtones. Although palette and warmtones are distinct lists, there remains indirect aliasing.
62
Deep Copy
• In a deep copy, the new copy references its own copies of those objects referenced by the
original version. In this application, we prefer that palette as a deep copy of warmtones.
• If we execute a command,
palette = copy. deepcopy(warmtones)
• It will explicitly make a copy of the original color instance rather than aliasing.
thank you

DSD Unit 1 Abstract Data Type data structures design notes.pptx

  • 1.
    Unit – 1 AbstractData Type DATA STRUCTURES DESIGN
  • 2.
    2 INTRODUCTION TO DATASTRUCTURES • Data structure is a branch of computer science. The study of data structure helps to understand how data is organized and how data flow is managed to increase the efficiency of any process or program. • Data structure is the structural representation of logical relationship between data elements. Definition Data structure is a way of storing, organizing and retrieving data in a computer, so that it can be used efficiently. It provides a way to manage large amount of data proficiently.
  • 3.
    3 Need for DataStructures  It gives different level of organization of data.  It tells how data can be stored and accessed.  It provides a means to manage large amount of data efficiently.  It provides fast searching and sorting of data. Classification of Data structures • Data structures can be classified into two categories. i) Primitive Data structures ii) Non-Primitive Data structures
  • 4.
    4 Primitive Data Structures •Primitive data structures are basic data structures. These can be manipulated or operated directly by the machine level instructions. Basic data types such as integer, real, character and Boolean come under this type. Example: int, char, float. Non-Primitive Data Structures  Non-primitive data structures are derived from primitive data structures.  These data structures cannot be operated or manipulated directly by the machine level instructions.  They define the group of homogeneous and non-homogenous data items.  Examples: Array, Lists, Graphs, Trees etc.
  • 5.
    5 1. Linear DataStructures  A data structure that maintains a linear relationship among the elements is called a linear data structure.  Here, the data are arranged in a sequential fashion. But in the memory the arrangement may not be sequential.  Examples: Arrays, linked lists, stack and queues. 2. Non-Linear Data Structures  A data structure that maintains the data elements in hierarchical order are known as nonlinear data structure. Thus, they are present at various levels.  They are comparatively difficult to implement and understand as compared to the linear data structures. Examples: Trees and Graphs.
  • 6.
    6 3. Static DataStructures • In static data structures the size of the structure is fixed. • The content of the data structures can be modified without changing the memory space allocated to it. Example: Array 4. Dynamic Data Structures In dynamic data structures the size of the structure is not fixed and can be modified during the operations performed on it. • Dynamic data structures are designed to facilitate change of data structures in the run time. Example: Linked list.
  • 7.
    7 ABSTRACT DATA TYPES(ADTs) • In the real-world, the programs evolve as a result of new requirements or constraints. So, a modification to a program commonly requires a change in one or more of its data structures. • For example, to add a new field to a student record, to keep track of more information about each student, then it will be better to replace an array with a linked structure to improve the program’s efficiency. In such a scenario, rewriting every procedure that uses the changed structure is not desirable. • Therefore, a better alternative is to separate the use of a data structure from the details of its implementation. This is the principle underlying use of abstract data type.
  • 8.
    8 • Definition • Anabstract data type or ADT is a mathematical abstraction. It specifies a set of operations (or methods) and the semantics of the operations (what they do), but it does not specify the implementation of the operations. • Examples: List ADT, Stack ADT, Queue ADT, Trees, Graphs etc. • The definition of ADT only mentions what operations are to be performed but not how these operations will be implemented. It does not specify how data will be organized in memory and what algorithms will be used for implementing the operations. It is called “abstract” because it gives an implementation-independent view. The process of hiding the nonessential details and providing only the essentials of problem solving is known as data abstraction.
  • 9.
    9 • The setof operations can be grouped into four categories. They are, • Constructors : Functions used to initialize new instances of the ADT at the time of instantiation. • Accessors : Functions used to access the data elements contained in an instance without making any modification to it. • Mutators : Functions that modify the data elements of an ADT instance. • Iterators : Functions that enable sequential access of the data elements.
  • 10.
    10 Advantages of usingADTs • ADTs give the feel of plug and play interface. So it is easy for the programmer to implement ADT. For example, to store collection of items, it can be easily put the items in a list. That is, BirdsList=[‘Parrot’,’Dove’,’Duck’,’Cuckoo’] • To find number of items in a list, the programmer can use len function without implementing the code. • The ADTs reduces the program developing time. Because the programmer can use the predefined functions rather than developing the logic and implementing the same. • The usage of ADTs reduces the chance of logical errors in the code, as the usage of predefined functions in the ADTs are already bug free. • ADTs provide well defined interfaces for interacting with the implementing code. • ADTs increase the understandability and modularity of the code.
  • 11.
    11 ADTs AND CLASSES •A data structure is the implementation for an ADT. In an object-oriented language, an ADT and its implementation together make up a class. Each operation associated with the ADT is implemented by a member function or method. The variables that define the space required by a data item are referred to as data members. An object is an instance of a class that is created and takes up storage during the execution of a computer program.
  • 12.
    12 In this way,the user can use an abstract data type to define new class by specifying attributes and operations.
  • 13.
    13 INTRODUCTION TO OBJECTORIENTED PROGRAMMING Goals, Principles and Patterns • The main ‘actors’ in the object-oriented paradigm are called objects. Each object is an instance of a class. • Each class presents to the outside world a concise and consistent view of the objects, that are instances of this class, without going into too much unnecessary detail or giving others access to the inner workings of the objects. • The class definition typically specifies instance variables, also known as data members, that the object contains, as well as the methods, also known as member functions, that the object can execute. • This view of computing is intended to fulfill several goals and incorporate several design principles.
  • 14.
    14 • Example 2: •Consider a user defined Student class with student_name, student_id and student_mark as its data members along with operations get_name(), put_name(), get_id(), put_id(), compute_marks() and display_marks(_) as the member functions. • This Student class would represent a composite type of data, named Student, consisting of student_name (String type), student_id (integer or string type) and student mark (float type). • • Thus, an instance of this student class represents an abstract view of the student details. The class Student can be considered to represent a data type that is abstract in nature. Thus, the classes are known to be abstract data type (ADT).
  • 15.
    15 Object-Oriented Design Goals •Software implementations should achieve robustness, adaptability, and reusability. Robustness • Every good programmer wants to develop software that is correct, which means that a program produces the right output for all the anticipated inputs in the program’s application. The software is said to be robust, if it is capable of handling unexpected inputs that are not explicitly defined for its application. For example, if a program is expecting a positive integer and instead is given a negative integer, then the program should be able to recover gracefully from this error.
  • 16.
    16 Adaptability • Modern softwareapplications, such as Web browsers and Internet search engines, involve large programs that are used for many years. Software, therefore, needs to be able to evolve over time in response to changing conditions in its environment. Thus, another important goal of quality software is that it achieves adaptability (also called evolvability). Related to this concept is portability, which is the ability of software to run with minimal change on different hardware and operating system platforms. An advantage of writing software in Python is the portability provided by the language itself. Reusability • Going hand in hand with adaptability, the software be reusable. That is, the same code should be usable as a component of different systems in various applications. Developing quality software is designed in a way that makes it easily reusable in future applications. Such reuse should be done with care.
  • 17.
    17 Object-Oriented Design Principles Theimportant principles in object-oriented approach, are as follows • Modularity  Abstraction  Encapsulation Modularity • Modern software systems consist of several different components that must interact correctly in order for the entire system to work properly. Keeping these interactions requires that these different components be well organized. Modularity refers to an organizing principle in which different components of software system are divided into separate functional units. • Modularity in a software system can provide a powerful organizing framework that brings clarity to an implementation. In Python, a module is a collection of closely related functions and classes that are defined together in a single file of source code. For example, Python’s standard library math module, provides definitions for key mathematical constants and functions, and the os module, provides support for interacting with the operating system. • The uses of modularity: • It increases the robustness of the program.  It is easier to test and debug separate components of the program.  It enables software reusability.
  • 18.
    18 Abstraction • Abstraction allowsdealing with the complexity of the object. Abstraction allows picking out the relevant details of the object, and ignoring the non-essential details. • Applying the abstraction to the design of data structures gives rise to Abstract Data Types (ADTs). An ADT is a mathematical model of a data structure that specifies the type of data stored, the operations supported on them, and the types of parameters of the operations. An ADT specifies what each operation does, but not how it does it. • Python supports abstract data types using a mechanism known as an abstract base class (ABC). An abstract base class cannot be instantiated (i.e., you cannot directly create an instance of that class), but it defines one or more common methods that all implementations of the abstraction must have. An ABC is realized by one or more concrete classes that inherit from the abstract base class while providing implementations for those method declared by the ABC.
  • 19.
    19 Encapsulation • Encapsulation meansinformation hiding. It hides the data defined in the class. Encapsulation separates implementation of the class from its interface. The interaction with the class is through the interface provided by the set of methods defined in the class. This separation of interface from its implementation allows changes to be made in the class without affecting its interface. • One of the advantages of encapsulation is that it gives freedom to the programmer to implement the details of a component, without concern that other programmers will be writing the code that intricately depends on those internal decisions. The only constraint on the programmer of a component is to maintain the public interface for the component, as the other programmers will be writing the code that depends on that interface.
  • 20.
    20 Object Oriented DesignPatterns • Object-oriented design facilitates reusable, robust, and adaptable software. Designing good code requires the effective use of object-oriented design techniques. • Computing researchers and practitioners have developed a variety of organizational concepts and methodologies for designing quality object-oriented software that is concise, correct, and reusable. • The concept of a design pattern, describes a solution to a “typical” software design problem. A pattern provides a general template for a solution that can be applied in many different situations. • It describes the main elements of a solution in an abstract way that can be specialized for a specific problem at hand. The design pattern can be consistently applied to implementations of data structures and algorithms. • These design patterns fall into two groups patterns for solving algorithm design problems and patterns for solving software engineering problems.
  • 21.
    21 • The algorithmdesign patterns include the following:  Recursion  Amortization  Divide and conquer  Prune and search  Brute force  Dynamic Programming  The greedy method Likewise, the software engineering design patterns include:  Iterator  Adapter  Position  Composition  Template method  Locator
  • 22.
    22 CLASSES IN PYTHON •A class serves as the primary means for abstraction in object-oriented programming. In python everything is an object. Everything is an instance of some class. A class also serves as a blueprint for its instances.  The data values stored inside an object are called attributes. The state information for each instance is represented in the form of attributes (also known as fields, instance variables, or data members).  A class provides a set of behaviors in the form of member functions (also known as methods), with implementations that are common to all instances of that class.
  • 23.
    23 Defining a class Aclass is the definition of data and methods for a specific type of object. • Syntax: class classname: <statement1> . . . <statement> The class definition begins with the keyword class, followed by the name of the class, a colon and an indented block of code that serves as the body of the class. The body includes definitions for all methods of the class. These methods are defined as functions, with a special parameter, named self, that is used to identify the particular instance upon which a member is invoked. When a class definition is entered, a new namespace is created, and used as the local scope. Thus, all assignments to local variables go into this new namespace.
  • 24.
    24 • Example: class customer: def_ _init_ _(self,name,iden,acno): self.custName=name self.custID=iden self.custAccNo=acno def display(self): print("Customer Name = ",self.custName) print("Customer ID = ",self.custID) print("Customer Account Number = ",self.custAccNo) c = customer("Ramesh",10046,327659) c.display()
  • 25.
    25 The Self Identifierand Self Parameter • In python, the self-identifier places a key role. Self identifies the instance upon which a method is invoked. While writing function in a class, at least one argument has to be passed, that is called self-parameter. The self-parameter is a reference to the class itself and is used to access variables that belongs to the class. • In python programming self is a default variable that contains the memory address of the instance of current class. So self is used to reuse all the instance variable and instance methods. • Example: self.custName, self.custID, self.custAccNo •
  • 26.
    26 Object Creation  Anobject is the runtime entity used to provide the functionality to the python class.  The attributes defined inside the class are accessed only using objects of that class.  The user defined functions also accessed by using the object.  As soon as a class is created with attributes and methods, a new class object is created with the same name as the class.  This class object permits to access the different attributes as well as to instantiate new objects of that class.  Instance of the object is created using the name same as the class name and it is known as object instantiation.  One can give any name to a newly created object. Syntax: object_name = class_name The dot(.) operator is used to call the functions. Syntax: object_name . function_name()
  • 27.
    27 Class variable andInstance variable • Class variable is defined in the class and can be used by all the instances of that class.  Instance variable is defined in a method and its scope is only with in the object that defines it.  Every object of the class has its own copy of that variable. Any change made to the variable don’t reflect in other objects of that class.  Instance variables are unique for each instance, while class variables are shared by all instances.
  • 28.
    28 • Example: class Order: def_ _init_ _(self, coffee_name, price): self.coffee_name = coffee_name self.price = price ram_order = Order("Espresso", 210) print(ram_order.coffee_name) print(ram_order.price) paul_order = Order("Latte", 275) print(paul_order.coffee_name) print(paul_order.price) • In this example, coffee_name and price are the class variables. ram_order and paul_order are the two instances of this class. Each of these instances has their own values set for the coffee_name and price instance variables. • When ram’s order details are printed in the console, the values Espresso and 210 are returned. When Paul’s order details are printed in the console, the values Latte and 275 are returned. • This shows that, instance variables can have different values for each instance of the class, whereas class variables are the same across all instances.
  • 29.
    29 A constructor isa special method used to create and initialize an object of a class. This method is defined in the class. The constructor is executed automatically at the time of object creation. In python _ _init_ _() method is called as the constructor of the class. It is always called when an object is created. The primary responsibility of _ _init_ _ method is to establish the state of a newly created object with appropriate instance variables. Syntax: def _ _init_ _(self): #body of the constructor Where, def keyword is used to define function. _ _init_ _() method: It is a reserved method. This method gets called as soon as an object of a class is instantiated. self: The first argument self refers to the current object. It binds the instance to the _ _init_ _() method. It is usually named self to follow the naming convention. Example: class student: def __init__(self,rollno,name,age): self.rollno=rollno self.name=name self.age=age print("student object is created") s=student(1091,"Amala",21) print("Roll no of the student=",s.rollno) print("Name of the student=",s.name) print("Age of the student=",s.age) Output: Student object is created Roll no of the student=1091 Name of the student=Amala Age of the student=21 Constructor
  • 30.
    30 Types of constructors •There are three types of constructors 1. Default Constructor 2. Non-Parameterized Constructor 3. Parameterized Constructor  Python will provide a default constructor if no constructor is defined.  Python adds a default constructor when the programmer does not include the constructor in the class or forget to declare it.  Default constructor does not perform any task but initializes the objects. It is an empty constructor without a body.
  • 31.
    31 Non-Parametrized Constructor • Aconstructor without any arguments is called a non-parameterized constructor. This type of constructor is used to initialize each object with default values.  This constructor does not accept the arguments during object creation. Instead, it initializes every object with the same set of values. Example: class Employee: def _ _init_ _(self): self.name = "Ramesh" self.EmpId = 100456 def display(self): print("Employee Name = ", self.name, " nEmployee Id = ",self.EmpId) emp = Employee() emp.display() Output: Employee Name = Ramesh Employee Id = 100456
  • 32.
    32 Parameterized constructor •Constructor withparameters is known as parameterized constructor. •The first parameter to constructor is self that is a reference to the being constructed, and the rest of the arguments are provided by the programmer. A parameterized constructor can have any number of arguments. Example: class Employee: def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary def display(self): print(self.name, self.age, self.salary) # creating object of the Employee class emp1 = Employee('Banu', 23, 17500) emp1.display() emp2 = Employee('Jack', 25, 18500) emp2.display() Output: Banu 23 17500 Jack 25 18500
  • 33.
    33 Destructor is aspecial method that is called when an object gets destroyed. A class can define a special method called destructor with the help of __del()__. In Python, destructor is not called manually but completely automatic, when the instance(object) is about to be destroyed. It is mostly used to clean up non memory resources used by an instance(object). Example: For Destructor class Student: # constructor def __init__(self, name): print('Inside Constructor') self.name = name print('Object initialized') def display(self): print('Hello, my name is', self.name) # destructor def __del__(self): print('Inside destructor') print('Object destroyed') # create object s1 = Student('Raja') s1.display() # delete object del s1 Output: Inside Constructor Object initialized Hello, my name is Raja Inside destructor Object destroyed Destructor
  • 34.
    34 Iterators  Iteration isan important concept in the design of data structures. An iterator is an object that contains a countable number of elements that can be iterated upon.  Iterators allows to traverse through all the elements of a collection and return one element at a time.  An iterator object must implement two special methods, iter() and next() collectively called iterator protocol.  An object is called iterable if it gets an iterator from it. Most built-in containers in python are, list, tuple, string etc.  The _ _iter_ _() method returns the iterator object itself. If required, some initialization can be performed.  The _ _next_ _() method returns the next element of the collection. On reaching the end, it must raise stop Iteration exception to indicate that there are no further elements.
  • 35.
    35 class sequencegen: def __init__(self,limit): self.limit=limit def__iter__(self): self.x=1 return self def __next__(self): x=self.x if x>self.limit: raise StopIteration() else: self.x=x+1 return x for i in sequencegen(5): print(i) Output: 1 2 3 4 5
  • 36.
    36 • Encapsulation isone of the fundamental concepts in object-oriented programming. Encapsulation in Python describes the concept of bundling data and methods within a single unit. A class is an example of encapsulation as it binds all the data members ( instance variables) and methods into a single unit. ENCAPSULATION
  • 37.
    37 class Employee: def __init__(self,name, salary, project): # data members self.name = name self.salary = salary self.project = project # method to display employee's details def display(self): # accessing public data member print("Name: ", self.name, 'Salary:', self.salary) def work(self): print(self.name, 'is working on', self.project) # creating object of a class emp = Employee('Jess', 40000, 'Infosys') # calling public method of the class emp.display() emp.work() Output: Name: Jess Salary: 40000 Jess is working on Infosys In this example, an Employee class defining employee attributes such as name, salary and project as an instance variables and implementing its behavior using display() and work() instance methods. • Encapsulation, hide an object’s internal representation from the outside. This is called information hiding. • Encapsulation allows us to restrict accessing variables and methods directly and prevent accidental data modification by creating private data members and methods within a class.
  • 38.
    38 Data hiding usingaccess modifiers • Encapsulation can be achieved by declaring the data members and methods of a class either as private or protected. But in Python, there is no direct access modifiers like public, private, and protected. This can be achieved by using single underscore and double underscores. Single underscore represents the protected and double underscore represents the private members.
  • 39.
    39 Public data membersare accessible within and outside of a class. All member variables of the class are by default public. Example: class Employee: # constructor def __init__(self, name, salary): # public data members self.name = name self.salary = salary # public instance methods def display(self): # accessing public data member print("Name: ", self.name, 'Salary:', self.salary) # creating object of a class emp = Employee('Jess', 40000) # accessing public data members print("Name: ", emp.name, 'Salary:', emp.salary) # calling public method of the class emp.display() Output: Name: Jess Salary: 40000 Name: Jess Salary: 40000 Public Member
  • 40.
    40 The variables canbe protected in the class by marking them as private. To define a private member, prefix the variable name with two underscores. Private members are accessible only within the class. Example: Access private member outside of a class using an instance method. class Employee: # constructor def __init__(self, name, salary): # public data member self.name = name # private member self.__salary = salary # public instance methods def display(self): # private members are accessible from a class print("Name: ", self.name, 'Salary:', self.__salary) emp = Employee('Jess', 40000) emp.display() Output: Name: Jess Salary: 40000 Private Member
  • 41.
    41 Protected members areaccessible within the class and also available to its sub-classes. To define a protected member, prefix the member name with a single underscore. Protected data members are used in inheritance and to allow data members access to only child classes. Example: Protected member in inheritance. class Company: def _ _init_ _(self): # Protected member self._project = "Infosys" class Employee(Company): def _ _init_ _(self, name): self.name = name Company._ _init_ _(self) def display(self): print("Employee name :", self.name) # Accessing protected member in child class print("Working on project :", self._project) c = Employee("Jess") c.display() # Direct access protected data member print('Project:', c._project) Output: Employee name : Jess Working on project : Infosys Project: Infosys Protected Member
  • 42.
    42 Advantages of Encapsulation 1.The main advantage of using encapsulation is the security of the data. Encapsulation protects an object from unauthorized access. 2. Encapsulation hide an object’s internal representation from the outside called data hiding. 3. It simplifies the maintenance of the application by keeping classes separated and preventing them from tightly coupling with each other. 4. Bundling data and methods within a class makes code more readable and maintainable.
  • 43.
    43 OPERATOR OVERLOADING Operator overloadingmeans giving extended meaning beyond their predefined operational meaning. For example, operator + is used to add two integers as well as join two strings and merge two lists. The same built-in operator or function shows different behavior for objects of different classes, this is called operator overloading. Example: # add 2 numbers print(100 + 200) # concatenate two strings print('Python' + 'Programming') # merger two list print([10, 20, 30] + ['Data Structures', 'And', 'Algorithms']) Output: 300 PythonProgramming [10, 20, 30, 'Data Structures', 'And', 'Algorithms'] The operator + is used to carry out different operations for distinct data types. This is one of the simplest occurrences of polymorphism in Python.
  • 44.
    44 To perform operatoroverloading, python provides some special function or magic function that is automatically invoked when it is associated with the particular object. If + operator is used, the magic method _add_ is automatically invoked. Example: class item: def _ _init_ _(self, price): self.price = price # Overloading + operator with magic method def _ _add_ _(self, other): return self.price + other.price b1 = item(400) b2 = item(300) print("Total Price: ", b1 + b2) Output: Total Price: 700 In this example, addition is implemented by a special method in python called the _add_ method. When two integers are added together, this method is called to create a new integer object.
  • 45.
    45  Executing x+y,calls the int class _add_ method when x is an integer, but it calls the float types _add_ method when x is float. The operand on the left-hand side determines which add method is called. Thus the + operator is overloaded.  When a binary operator is applied to two instances of different types, as in 5 * ‘Hello’, Python gives deference to the class of the left operand.  In this example, Python would effectively check if the int class provides a sufficient definition for how to multiply an instance by a string, via the _ _mul_ _ method. If that class does not implement such a behavior, Python checks the class definition for the right-hand operand, in the form of a special method named _ _rmul_ _ (i.e., right multiply). This provides a way for a new user-defined class to support mixed operations that involve an instance of an existing class.
  • 46.
    46 INHERITANCE • A naturalway to organize various structural components of a software package is in a hierarchical fashion.  A hierarchical design is useful in software development, as common functionality can be grouped at the most general level, thereby promoting reuse of code, while differentiated behaviors can be viewed as extensions of the general case.  In object-oriented programming the mechanism for a modular and hierarchical organization is a technique known as inheritance. This allows a new class to be defined based upon an existing class as the starting point.  In object-oriented programming, the existing class is typically described as the base class, parent class or super class, while the newly defined class is known as the subclass or child class.  There are two ways in which a subclass can differentiate itself from its superclass. A subclass may specialize an existing behavior by providing a new implementation that overrides an existing method. A subclass may also extend its superclass by providing brand new methods.  Inheritance is a mechanism through which we can create a class or object based on another class or object. In other words, the new objects will have all the features or attributes of the class or object on which they are based. It supports code reusability.
  • 47.
  • 48.
    48 In Python, basedupon the number of child and parent classes involved, there are five types of inheritance. The types of inheritance are listed below: i. Single inheritance ii. Multiple Inheritance iii. Multilevel inheritance iv. Hierarchical Inheritance v. Hybrid Inheritance Single Inheritance In single inheritance, a child class inherits from a single-parent class. Here is one child class and one parent class.
  • 49.
    49 Example: # Base class classVehicle: def Vehicle_info(self): print('Inside Vehicle class') # Child class class Car(Vehicle): def car_info(self): print('Inside Car class') # Create object of Car car = Car() # access Vehicle's info using car object car.Vehicle_info() car.car_info() Output: Inside Vehicle class Inside Car class Here class car inherits from class Vehicle.
  • 50.
    50 • In multipleinheritance, one child class can inherit from multiple parent classes. So here is one child class and multiple parent classes. # Parent class 1 class Person: def person_info(self, name, age): print('Inside Person class') print('Name:', name, 'Age:', age) # Parent class 2 class Company: def company_info(self, company_name, location): print('Inside Company class') print('Name:', company_name, 'location:', location) # Child class class Employee(Person, Company): def Employee_info(self, salary, skill): print('Inside Employee class') print('Salary:', salary, 'Skill:', skill) # Create object of Employee emp = Employee() # access data emp.person_info('Jessica', 28) emp.company_info('YouTube', ' California ') emp.Employee_info(12000, 'Cloud Computing') Output: Inside Person class Name: Jessica Age: 28 Inside Company class Name: YouTube location: California Inside Employee class Salary: 12000 Skill: Cloud Computing Multiple Inheritance
  • 51.
  • 52.
    52 • In multilevelinheritance, a class inherits from a child class or derived class. Suppose three classes A, B, C. A is the superclass, B is the child class of A, C is the child class of B. In other words, a chain of classes is called multilevel inheritance. # Base class class Vehicle: def Vehicle_info(self): print('Inside Vehicle class') # Child class class Car(Vehicle): def car_info(self): print('Inside Car class') # Child class class SportsCar(Car): def sports_car_info(self): print('Inside SportsCar class') # Create object of SportsCar s_car = SportsCar() # access Vehicle's and Car info using SportsCar object s_car.Vehicle_info() s_car.car_info() s_car.sports_car_info() Output: Inside Vehicle class Inside Car class Inside SportsCar class Multilevel Inheritance
  • 53.
    53 Hierarchical Inheritance • InHierarchical inheritance, more than one child class is derived from a single parent class. In other words, one parent class and multiple child classes. class Vehicle: def info(self): print("This is Vehicle") class Car(Vehicle): def car_info(self, name): print("Car name is:", name) class Truck(Vehicle): def truck_info(self, name): print("Truck name is:", name)
  • 54.
    54 obj1 = Car() obj1.info() obj1.car_info('BMW') obj2= Truck() obj2.info() obj2.truck_info('Ford') Output: This is Vehicle Car name is: BMW This is Vehicle Truck name is: Ford •
  • 55.
    55 • When inheritanceconsists of multiple types or a combination of different inheritance then it is called hybrid inheritance. class Vehicle: def vehicle_info(self): print("Inside Vehicle class") class Car(Vehicle): def car_info(self): print("Inside Car class") class Truck(Vehicle): def truck_info(self): print("Inside Truck class") # Sports Car can inherits properties of Vehicle and Car class SportsCar(Car, Vehicle): def sports_car_info(self): print("Inside SportsCar class") # create object s_car = SportsCar() s_car.vehicle_info() s_car.car_info() s_car.sports_car_info() Output: Inside Vehicle class Inside Car class Inside SportsCar class Hybrid Inheritance
  • 56.
    56 Namespaces  Whenever anidentifier is assigned to a value, its definition is made with a specific scope. Top level assignments are known as global scope. Assignments made with in the body of a function have local scope to that function call.  In Python, when computing a sum with the syntax x + y, the names x and y must have been previously associated with objects that serve as values. The process of determining the value associated with an identifier is known as name resolution.  A namespace manages all of the identifiers that are defined in a particular scope, mapping each name to its associated value. In Python, functions, classes and modules are class objects and so the value associated with an identifier in a namespace may be a function, class or module.  A namespace is a collection of currently defined symbolic names along with information about the object that each name references. We can think of a namespace as a dictionary, in which the keys are the object names and the values are the objects themselves. Each key-value pair maps a name to its corresponding object.
  • 57.
    57 Types of namespaces i)Built-in Namespace The built-in namespace contains the names of all of Python’s built-in objects. These are available at all times when Python is running. The Python interpreter creates the built-in namespace when it starts up. This namespace remains in existence until the interpreter terminates. Example: Name=input("Enter your name:") #input() is built-in function print(Name) #print() is built-in function
  • 58.
    58 Global Namespace •The globalnamespace contains any names defined at the level of the main program. Python creates the global namespace when the main program body starts, and it remains in existence until the interpreter terminates. •The interpreter creates a global namespace for any module that the program loads with the import statement. Example: x=10 # global scope of variable in python def f1(): #function definition print(x) #variable accessed inside the function f1()
  • 59.
    59 i) Local namespace InPython, the interpreter creates a new namespace whenever a function executes. That namespace is local to the function and remains in existence until the function terminates. A local namespace can access global as well as built-in namespaces. Example: def f1(): #function definition y=20 #Local scope of variable in python print(y) #variable accessed inside the function f1() • The variable ‘y’ is declared in a local namespace and has a local scope of variable in python.
  • 60.
    60 SHALLOW AND DEEPCOPYING • In some applications, it is necessary to subsequently modify either the original or copy in an independent manner. • Consider an application to manage various lists of colors. Each color is represented by an instance of a presumed color class. warmtones is an identifier denote an existing list of such colors (e.g., oranges, browns). • In this application, we wish to create a new list named palette, which is a copy of the warmtones list and subsequently wanted to add additional colors to palette, or to modify or remove some of the existing colors, without affecting the contents of warmtones. • If we execute the command, • palette = warmtones • This creates an alias as shown in figure and no new list is created. Instead, the new identifier palette references the original list. If we add or remove colors from palette, it will change the wormtones list also.
  • 61.
    61 Shallow Copy • Inshallow copy, the new list is initialized so that its contents are precisely same as the original sequence. • If we execute the command, palette = list (warmtones) • It creates a new instance of the list. This is known as the shallow copy. • The new list represents a sequence of references to the same elements as in the first. We can add or remove elements from palette without affecting warmtones. • However, if we edit a color instance from the palette list, we effectively change the contents of warmtones. Although palette and warmtones are distinct lists, there remains indirect aliasing.
  • 62.
    62 Deep Copy • Ina deep copy, the new copy references its own copies of those objects referenced by the original version. In this application, we prefer that palette as a deep copy of warmtones. • If we execute a command, palette = copy. deepcopy(warmtones) • It will explicitly make a copy of the original color instance rather than aliasing.
  • 63.