Monday, May 13, 2024

I.M.C.A / B.C.A. Semester – 3 Data Science Fundamentals With Python Unit – 4

 

 

I.M.C.A Semester – 3

Data Science Fundamentals

With Python

Unit – 4


Contents

OOP in Python. 3

Defining Class for Object 5

Immutable and mutable object 8

Data Hiding Fields. 11

Class Abstraction and Encapsulation. 15

Super Class and Sub Class. 18

Overriding Methods. 21

Polymorphism and Dynamic Binding. 24

 

 

Object-Oriented Programming (OOP) is a programming paradigm that organizes code into objects, which are instances of classes.

Python is an object-oriented programming language that fully supports OOP principles. In Python, everything is an object, and you can create your own custom objects by defining classes.

Lets break down the key concepts of OOP in Python:

 

1. Class: A class is a blueprint or a template for creating objects. It is a collection of member variables and member functions which will accessed by an object.

In Python, you can define a class using the class keyword.

 

2. Object: An object is an instance of a class. You create objects based on the structure defined in the class.

Each object has its own set of attributes and can execute methods defined in the class. but you can create a hierarchy of classes.

Attributes are variables that store data within an object. You can access and modify these attributes using dot notation.

 

3. Inheritance: Inheritance allows you to create a new class (subclass) that inherits attributes and methods from an existing class (superclass or base class).

Python supports single inheritance, where a subclass can inherit from only one superclass.

This promotes code reusability and allows you to extend or modify the behaviour of existing classes without changing their code.

4. Encapsulation: Encapsulation is the concept of bundling data (attributes) and the methods that operate on that data into a single unit (a class).

It helps to hide the internal implementation details of a class and only expose a well-defined interface.

Python supports encapsulation through the use of private and protected attributes and methods.

 

5. Polymorphism: Polymorphism is a Latin word in which poly means many and morphism means forms, so The word polymorphism means having many forms.

There are two types of polymorphism which are

1.     Compile-time polymorphism also called - (Method overloading)

2.     Run-time polymorphism also called - (Method overriding).

 

6. Abstraction: Abstraction is used to hide the internal functionality of the function from the users. The users only interact with the basic implementation of the function, but inner working is hidden. User is familiar with that "what function does" but they dont know "how it does."

It helps in managing the complexity of large software systems.

 

Pythons support for OOP makes it a powerful language for creating modular, reusable, and maintainable code.


 

Python is an object-oriented programming language that fully supports OOP principles. In Python, everything is an object, and you can create your own custom objects by defining classes.

A class is a blueprint or a template for creating objects. It is like a template that describes the structure and behaviour of objects that will be created based on it.

Class is a collection of member variables and member functions which will accessed by an object.

In Python, an object is a fundamental concept that represents a unique instance of a class.

Objects are the building blocks of object-oriented programming (OOP) in Python, and they encapsulate both member variables and member methods within a single unit.

In Python, you can define a class using the class keyword. followed by the class name and a colon.

Following is a syntax to define class in python:

class MyClass:

          #Member Variables

          #Member Methods

According to above syntax class is a keyword used to create a class in python.

MyClass is a name of class, and than define (:) colon to separate the block of class in python.

Member Variables: Member variables, also known as instance variables ,that are associated with objects created from a class. Each object of a class has its own copy of these variables, and they store data specific to that object.

Member variables are defined within the class and are accessed using the self keyword within methods of the class.

Member Methods: In Python, member methods are also known as instance methods, which are functions defined within a class and operates member variables and behaviour of objects created from that class.

Following are some rules of defining name of class in python:

Class names typically start with an uppercase letter by convention.

Class name can not be any keywords name.

Class name can not start with any number or special Character. we can use ( _ )
underscore with class name.

Object:

An Object is an Instance of Class. It is created from a class, which serves as a blueprint or template.

 

1. Attributes: Objects have attributes, which are variables that store data specific to that instance. These attributes can be accessed and modified through the object.

 

2. Methods: Objects can perform actions or provide functionality through methods, which are functions defined within the class and associated with instances of the class.

 

 

 

 

 

Following is an Example of Creating class for object:

class MyClass:

    a = 10

    def disp(self):

        print("Value of A = ",self.a + 10)

 

obj = MyClass()

obj.disp()

print(“Member Variable = ”,obj.a)

 

Output:

Value of A = 20

Member Variable = 10

In Python, objects are categorized into two main types based on whether their state (data) can be changed after they are created that are:

1.     Immutable

2.     Mutable objects.

 

Immutable Objects:

1. Immutable objects are objects whose state cannot be modified once they are created.

2. Examples of immutable objects in Python include integers, floating-point numbers, strings, tuples, and frozensets.

3. When you try to modify an immutable object, Python creates a new object with the updated value, leaving the original object unchanged.

 

Here is  an example:

 

x = 5    # x is an integer, which is immutable

y = x    # y now refers to the same integer object as x

 

# Attempting to modify x

x = x + 1    # value of x = 6

 

print(“Value of X = ”,x) 

print(“Value of Y = ”,y)

 

Output:

Value of X = 6

Value of Y = 5

 

Mutable Objects:

1. Mutable objects are objects whose state can be modified after they are created.

2. Examples of mutable objects in Python include lists, dictionaries, sets, and user-defined classes (if they allow changes to their attributes).

3. When you modify a mutable object, you are directly altering the objects internal state, and other variables referencing the same object will see the changes.

 

Here is an example:

 

list1 = [1, 2, 3]     # list1 is a mutable list

 

list2 = list1    # list2 now refers to the same list object as list1

 

# Modifying the list through list1

list1.append(4)

 

print(“List 1 = ”,list1)

print(“List 2 = ”,list2)    # list2 reflects the changes made to list1 because they both refer to the same list object

Output:

List 1 = [1,2,3,4]

List 2 = [1,2,3,4]

 

Understanding the distinction between mutable and immutable objects is essential in Python, as it affects how you work with data and objects in your code.

Immutable objects guarantee that their values won’t change unexpectedly,

Mutable objects allow you to modify their content directly.


 

Python is high-level , Object Oriented Programming Language that supports all the principals of OOP and data hiding is one the most important principal of OOPs.

Data hiding, often referred to as encapsulation, is a fundamental concept in object-oriented programming (OOP) that allows you to restrict access to certain attributes or methods of a class from the outside world.

This concept helps ensure the integrity and security of data within objects and promotes good coding practices by separating the implementation details from the interface exposed to external code.

In Python, data hiding fields are typically implemented using:

1.     Naming conventions

2.     Access control mechanisms.

Here is how this fields works:

 

1) Naming Conventions:

   In Python, there are naming conventions to indicate the level of visibility for attributes and methods. These naming conventions use underscores as prefixes:

A single underscore prefix: (e.g., _variable) indicates that the attribute or method is intended to be protected. Its a signal to other programmers that this attribute should not be accessed directly from outside the class, but its not enforced by the Python interpreter. Its more of a convention and a hint for developers.

 

A double underscore prefix: (e.g., __variable) invokes name mangling. Python will rename the attribute with the class name as a prefix, making it less accessible from outside the class. However, its still technically possible to access the attribute with the mangled name.

 

2) Access Control:

Python provides access control mechanisms through which you can control the visibility of attributes and methods. Although Python does not enforce strict access control like some other languages (e.g., Java), you can achieve data hiding by using access control levels:

 

1.     Public: Attributes and methods without a prefix are considered public and can be accessed from anywhere, both inside and outside the class.

 

2.     Protected: Attributes and methods with a single underscore prefix are considered protected, and by convention, they should not be accessed from outside the class. However, they can still be accessed if necessary.

 

3.     Private: Attributes and methods with a double underscore prefix are considered private.

Python applies name mangling to the name of the member. Name mangling means that the name of the member is altered to include the class name as a prefix.

For example, if you have a class MyClass with a private variable __my_private_var, the actual name becomes _MyClass__my_private_var. This makes it more difficult to access the member from outside the class.

 

 

 

 

Heres an example to illustrate data hiding in Python:

class MyClass:

    def __init__(self):

        self.public_var = "Im a public variable"

        self._protected_var = "Im a protected variable"

        self.__private_var = "Im a private variable"

        def public_method(self):

            return "Im a public method"

 

     def _protected_method(self):

            return "Im a protected method"

 

        def __private_method(self):

            return "Im a private method"

 

obj = MyClass()

print(obj.public_var)

print(obj.public_method())

 

print(obj._protected_var)

print(obj._protected_method())

 

print(obj._MyClass__private_var)

print(obj._MyClass__private_method())

Output:

Im a public variable

Im a public method

Im a protected variable

Im a protected method

Im a private variable

Im a private method


 

Python is a general purpose , high-level , Object Oriented Programing Language. It is fully supports OOP principles. In Python, everything is an object, and you can create your own custom objects by defining classes.

In python class is a blueprint or template for creating object and it is a collection of member variables and member function which will accessed by object.

Class abstraction and encapsulation are two fundamental concepts in object-oriented programming (OOP) that help in designing and structuring classes in Python  to create more organized, maintainable, and secure code.

 

1. Class Abstraction:

Abstraction is one of the basic building blocks of Object oriented programming.

Data abstraction and encapsulation are synonymous as data abstraction is achieved through encapsulation.

Abstraction is a process of hiding unnecessary data, and showing only relevant data to the external world , in order to reduce complexity and increase efficiency.

For example In our daily life, we use appliances like TV, Refrigerator, Washing Machine etc to meet some specific needs. We are not aware of its internal working or we are not interested to know about. We just operate them, profoundly their internal implementation is abstracted from us.

In Python, class abstraction is typically achieved through the definition of Abstract Base Classes (ABCs) using the abc module. This is an in-built module in python that provide methods to perform abstraction.

 

Key points about class abstraction:

Abstract Base Classes (ABCs):

In Python, abstract base classes are used to define abstract methods and properties. To perform abstraction in python we must have to import abc module

Abstract methods are methods that are declared but do not have an implementation in the base class.

Subclasses must provide implementations for these methods. Abstract properties are similar but for attributes.

Following is syntax to import ABC module:

from abc import ABC,abstractmethod

 

Abstraction in Action: Class abstraction helps in defining a common interface for related classes and ensuring that subclasses implement required methods, and simplifying code maintenance.

 

2. Encapsulation:

Encapsulation is the concept of bundling the data (attributes) and methods (functions) that operate on the data into a single unit called a class. It restricts direct access to some of an objects components, providing a level of data protection and organization. In Python, encapsulation is typically implemented using access control mechanisms (public, protected, and private) and naming conventions.

 


 

Key points about encapsulation:

Access Control: In Python, access control is not as strict as in some other languages, but conventions and naming patterns are used to indicate the intended visibility of attributes and methods. These conventions include:

Public: Members (attributes and methods) without a prefix are considered public and can be accessed from anywhere.

Protected: Members with a single underscore prefix (e.g., _variable) are considered protected and should not be accessed from outside the class, but this is not enforced by the language.

Private: Members with a double underscore prefix (e.g., __variable) are considered private, and cannot easily access outside of class without particular class name.

 

Encapsulation in Action: Encapsulation helps in organizing code, preventing unauthorized access or modification of data, and providing controlled access to data through methods.

It also allows for future changes to the internal implementation of a class without affecting external code that uses the class.

In summary, class abstraction and encapsulation are key principles in OOP that promote code organization, maintainability, and security.

Abstraction focuses on modeling classes based on essential characteristics and behaviors

While encapsulation bundles data and methods into a single unit and controls access to them. In Python, these concepts are achieved through the use of abstract base classes, access control mechanisms, and naming conventions.


 

In Python, the concepts of super classes which is also known as base classes or parent classes and subclasses which is also known as derived classes or child classes are fundamental to object-oriented programming (OOP).

These concepts are used to create class hierarchies and implement inheritance, which is a core principle in OOP.

Inheritance:

Inheritance is the mechanism by which a subclass can inherit attributes and methods from a superclass. It allows you to create new classes that are based on existing classes, promoting code reuse and modularity.

In Python, you specify the superclass in the class definition, and the subclass automatically inherits the attributes and methods of the superclass.

Heres an explanation of superclasses and subclasses in Python:

 

1. Superclass (Base Class):

A superclass (or base class) is a class that is used as a template or blueprint to define the common attributes and methods shared by one or more classes.

Super classes are typically more general and abstract in nature, representing a broader category or concept.

Super classes are defined using the class keyword like any other class, but they may include attributes and methods that are meant to be inherited by subclasses.


 

2. Subclass (Derived Class):

A subclass (or derived class) is a class that inherits attributes and methods from a superclass. It is more specific and can have additional attributes and methods of its own.

Subclasses are created using the class keyword, and they are defined by specifying the superclass in parentheses as part of the class definition.

Subclasses inherit the attributes and methods of the superclass and can also override (replace) or extend (add to) them.

Following is a simple example of Superclass and Subclass declaration:

class Super:

    def disp1(self):

        print("Super Class")

 

class Sub(Super):

     def disp2(self):

         print("Sub Class")

 

obj = Sub()

obj.disp1()

obj.disp2()

 

Output:    

Super Class

Sub Class

 

According to above example class is a keyword used to define class in python. Here Super is superclass that contain one function name disp1() and Sub is subclass that contain one function disp2() and also inherits the Super class function using (Super) parenthesis.

So here Sub class already inherits the properties of Super class , we create an object of Sub class which can access the methods of both class Super and Sub.


 

Method overriding is a fundamental concept in object-oriented programming (OOP) that allows a subclass to provide a specific implementation for a method that is already defined in its superclass (or parent class).

This allows you to customize or extend the behaviour of the inherited method in the subclass. Method overriding is a form of polymorphism in OOP.

 

Heres how method overriding works in Python:

 

1. Inheritance: First, you need a superclass and a subclass. The method to be overridden is defined in the superclass.

 

2. Same Method Signature: The overriding method in the subclass must have the same name, parameters, and return type (or a compatible subtype) as the method in the superclass.

 

3. @Override Annotation (Optional): While some programming languages require an @Override annotation to indicate method overriding, Python does not have such an annotation. Instead, Python relies on the method name and signature to identify the overridden method.

 

4. Custom Implementation: In the subclass, you provide a custom implementation for the method you want to override. This implementation should replace or extend the behaviour of the superclass method.

 

 

 

Following is an example of Method Overriding:

class A:

    def disp(self):

        print("Class-A Method")

class B(A):

    def disp(self):

        print("Class-B Method")

obj1 = B()

obj1.disp()

 

obj2 = A()

obj2.disp()

 

Output:

Class-B Method

Class-A Method

 

According to above example class is a keyword used to define class in python.

Here A is Super class that contain method name disp() and B is a Sub class that inherits Super class A and also contain method name disp().

Here the method disp() is same in both Super class and Sub class so, to access both methods we have to create objects of Class A and B.

So here Obj1 and obj2 both are individual Objects of class.

Method overriding allows you to create more specific behavior in subclasses while reusing the interface and structure defined in the superclass.

Its a powerful mechanism for achieving polymorphism, where different objects can respond differently to the same method call, based on their specific implementations.


 

In Python, polymorphism and dynamic binding are fundamental concepts that play a significant role in object-oriented programming (OOP).

 

They enable you to write more flexible and extensible code by allowing objects of different types to respond to the same method call in a way that is specific to their individual classes.

 

Polymorphism in Python:

Polymorphism is Latin word in which poly means many and morphism means form, so polymorphism is defined as many forms.

Polymorphism allows us to perform a single action in different ways.

Polymorphism allows you to write code that can work with objects of different classes in a unified and flexible manner, making your code more adaptable and extensible.

 

Basically there are two types of polymorphisms:

1.     Compile Time Polymorphism

2.     Run Time Polymorphism

 

Here's an example of polymorphism in Python:

In Python, there are two main types of polymorphism: compile-time (or static) polymorphism and runtime (or dynamic) polymorphism. These types of polymorphism are achieved through different mechanisms.

 


 

1. Compile-Time Polymorphism (Static Polymorphism):

Function Overloading: In some programming languages like C++ or Java, you can define multiple functions with the same name in the same class, but with different parameter lists (different number or types of parameters). Python does not support traditional function overloading, as it uses dynamic typing.

 

Following is an Example of Overloading:

def add(a, b):

     return a + b

def add(a, b, c):

     return a + b + c

add(10,20,30)

 

Output:

60

 

According to above example only the second `add` function will be visible, and the first one will be overloaded on second function.

 

2. Runtime Polymorphism (Dynamic Polymorphism):

Method Overriding: In Python, you can create subclasses that inherit methods from a parent class. If a subclass defines a method with the same name as a method in its parent class, it overrides the parent class's method. This is known as method overriding and is a form of runtime polymorphism. The specific method that gets called depends on the type of the object during runtime.

 


Following is an Example of Overriding:

   class Bank:

       def disp(self):

           pass

 

class SBI(Animal):

       def disp(self):

           return "SBI Bank"

 

   class ICIC(Animal):

       def disp(self):

           return "ICIC Bank"

 

   sbi = SBI()

   icic = ICIC()

 

   print(sbi.disp())

   print(icic.disp())

 

Output:

SBI Bank

ICIC Bank

 

In this example, both `SBI` and `ICIC` are subclasses of `Bank`, and they override the `disp()` method to provide their own implementation.

Runtime polymorphism is the more common and widely used form of polymorphism in Python.

 

Dynamic Binding in Python:

Dynamic binding, also known as late binding or runtime binding, is the process by which the appropriate method implementation is determined at runtime based on the actual type of the object being referenced. It allows Python to select the correct method to call dynamically during program execution.

 

Python uses dynamic binding to achieve polymorphism. When you call a method on an object, Python looks up the method in the object's class hierarchy and invokes the most specific implementation based on the actual object's type. This happens at runtime, making Python a dynamically typed language.

 

Dynamic binding ensures that the correct method is called based on the object's type, as demonstrated in the polymorphism example above.

 

In summary, polymorphism and dynamic binding in Python enable you to write more flexible and extensible code by allowing different objects to respond to the same method call based on their individual types.


 

Thank You

:: Any Query::

Contact: Ruparel Education Pvt. Ltd.

Mobile No: 7600044051