The Python modules (1)
The Python modules (1)
16: Write a python program to create and use a user defined module for a given
problem
Python's power is significantly enhanced by its extensive collection of built-in modules. These
modules provide pre-written code for a wide range of tasks, eliminating the need to reinvent the
wheel. Here's a breakdown of some commonly used and important built-in modules:
Core Functionality:
● os:
○ Provides an interface to the operating system.
○ Functions for file and directory manipulation, process management, and environment
variables.
● sys:
○ Provides access to system-specific parameters and functions.
○ Command-line arguments, standard input/output, and system paths.
● math:
○ Mathematical functions and constants (e.g., trigonometric, logarithmic, exponential).
● random:
○ Generates pseudo-random numbers.
○ Functions for random selection, shuffling, and generating random values.
● datetime:
○ Works with dates and times.
○ Provides classes for representing dates, times, and time intervals.
● time:
○ Time-related functions.
○ Measuring execution time, pausing execution, and working with time representations.
● io:
○ Input/output operations.
○ Working with streams of data (files, memory buffers).
● json:
○ Working with JSON (JavaScript Object Notation) data.
○ Encoding and decoding JSON.
● re:
○ Regular expressions.
○ Pattern matching and text manipulation.
● collections:
○ Specialized container datatypes (e.g., deque, Counter, defaultdict).
○ Enhanced data structures beyond basic lists, tuples, and dictionaries.
● typing:
○ Support for type hints.
○ Enables static type checking to improve code quality.
● socket:
○ Low-level network communication.
○ Creating network sockets for TCP/IP and UDP connections.
● http:
○ HTTP clients and servers.
● urllib:
○ Working with URLs.
○ Fetching data from web pages.
● csv:
○ Working with CSV (Comma Separated Values) files.
● pickle:
○ Object serialization.
○ Saving and loading Python objects to/from files.
● sqlite3:
○ SQLite database interface.
○ Working with SQLite databases.
● zlib:
○ Compression and decompression of data.
● threading:
○ Thread-based parallelism.
● multiprocessing:
○ Process-based parallelism.
● argparse:
○ Parsing command-line arguments.
● logging:
○ Logging messages for debugging and monitoring.
● unittest:
○ Unit testing framework.
● hashlib:
○ Secure hashes and message digests.
1. Import: Use the import statement to bring a module into your code.
○ import os
2. Access Functions: Use the module name followed by a dot (.) to access functions and
variables within the module.
○ os.getcwd()
The Python math module provides access to a wide range of mathematical functions and
constants. It's a fundamental tool for numerical computations in Python. Here's a breakdown of its key
features:
import math
# Constants
print("Constants:")
print(f"pi: {math.pi}")
print(f"e: {math.e}")
print(f"tau: {math.tau}")
print(f"inf: {math.inf}")
print(f"nan: {math.nan}")
print("-" * 20)
# Trigonometric Functions
print("Trigonometric Functions:")
print(f"acos(0): {math.acos(0)}")
print(f"asin(1): {math.asin(1)}")
print(f"atan(1): {math.atan(1)}")
print(f"atan2(1, 1): {math.atan2(1, 1)}")
print(f"cos(0): {math.cos(0)}")
print(f"dist((1, 1), (4, 5)): {math.dist((1, 1), (4, 5))}")
print(f"hypot(3, 4): {math.hypot(3, 4)}")
print(f"sin(math.pi / 2): {math.sin(math.pi / 2)}")
print(f"tan(0): {math.tan(0)}")
print(f"degrees(math.pi): {math.degrees(math.pi)}")
print(f"radians(180): {math.radians(180)}")
print("-" * 20)
# Hyperbolic Functions
print("Hyperbolic Functions:")
print(f"acosh(2): {math.acosh(2)}")
print(f"asinh(1): {math.asinh(1)}")
print(f"atanh(0.5): {math.atanh(0.5)}")
print(f"cosh(0): {math.cosh(0)}")
print(f"sinh(0): {math.sinh(0)}")
print(f"tanh(1): {math.tanh(1)}")
print("-" * 20)
# Special Functions
print("Special Functions:")
print(f"erf(0): {math.erf(0)}")
print(f"erfc(0): {math.erfc(0)}")
print(f"gamma(5): {math.gamma(5)}")
print(f"lgamma(5): {math.lgamma(5)}")
print("-" * 20)
The Python os module provides a portable way of using operating system dependent functionality.
It allows your Python scripts to interact with the underlying operating system, performing tasks like file
manipulation, directory navigation, process management, and more. Here's a breakdown of
commonly used functions and features:
Key Functionality:
# Create a directory
try:
os.mkdir("test_dir")
print("Directory 'test_dir' created.")
except FileExistsError:
print("Directory 'test_dir' already exists.")
Key Functionality:
● Integer Functions:
○ random.randint(a, b): Returns a random integer N such that a <= N <= b.
○ random.randrange(start, stop[, step]): Returns a randomly selected
element from range(start, stop, step).
● Sequence Functions:
○ random.choice(seq): Returns a random element from the non-empty sequence
seq.
○ random.choices(population, weights=None, *, cum_weights=None,
k=1): Returns a k sized list of elements chosen from the population with replacement.
○
○ random.shuffle(x): Shuffle the sequence x in place.
○ random.sample(population, k): Returns a k length list of unique elements
chosen from the population sequence.
● Real-Valued Distributions:
○ random.random(): Returns the next random floating point number in the range [0.0,
1.0).
○ random.uniform(a, b): Returns a random floating point number N such that a <=
N <= b for a <= b and b <= N <= a for b < a.
○ random.triangular(low, high, mode): Returns a random floating point
number N such that low <= N <= high and with the specified mode between those
bounds.
○ random.betavariate(alpha, beta): Beta distribution.
○
○ random.expovariate(lambd): Exponential distribution.
○ random.gammavariate(alpha, beta): Gamma distribution.
○ random.gauss(mu, sigma): Gaussian distribution.
○ random.lognormvariate(mu, sigma): Log normal distribution.
○ random.normalvariate(mu, sigma): Normal distribution.
○ random.vonmisesvariate(mu, kappa): Von Mises distribution.
○ random.paretovariate(alpha): Pareto distribution.
○ random.weibullvariate(alpha, beta): Weibull distribution.
● Seeding:
○ random.seed(a=None, version=2): Initialize the random number generator.
import random
# Integer functions
print("Random integer between 1 and 10:", random.randint(1, 10))
print("Random range element:", random.randrange(0, 10, 2))
# Sequence functions
my_list = [1, 2, 3, 4, 5]
print("Random choice from list:", random.choice(my_list))
print("Sample of 3 unique elements:", random.sample(my_list, 3))
random.shuffle(my_list)
print("Shuffled list:", my_list)
print("choices with replacement:", random.choices(my_list, k = 4))
# Real-valued distributions
print("Random float between 0 and 1:", random.random())
print("Random float between 5 and 10:", random.uniform(5, 10))
print("Gaussian distribution:", random.gauss(0, 1))
# Seeding
random.seed(42) # Set seed for reproducibility
print("Random number with seed 42:", random.random())
random.seed(42) # reset the seed to reproduce the previous random number.
print("Random number with seed 42 again:", random.random())
Practical No. 18: Write python program to create and use a user defined package for a given
problem
# File: my_package/geometry.py
def calculate_area_rectangle(length, width):
"""Calculates the area of a rectangle."""
return length * width
# File: my_package/greetings.py
def greet(name):
"""Greets a person by name."""
return f"Hello, {name}!"
# File: my_package/__init__.py
# This file marks the directory as a package
# File: main.py
import my_package.geometry as geometry
import my_package.greetings as greetings
length = 5
width = 10
name = "Alice"
greeting = greetings.greet(name)
print(greeting)
○ Inside my_package, create Python files for your modules. In this example, we have
geometry.py and greetings.py.
○ Define your functions within these modules (e.g., calculate_area_rectangle in
geometry.py, greet in greetings.py).
3. Create __init__.py:
○ Create an empty file named __init__.py inside the my_package directory. This file
tells Python to treat the directory as a package.
4. Create main.py:
Key Concepts:
● Organization: Packages help to organize your code into logical units, making it easier to
manage and maintain.
● Reusability: You can reuse your packages in multiple projects.
● Namespace Management: Packages provide a hierarchical namespace to avoid naming
conflicts between modules.
# Practical No. 19: Numpy and Matplotlib
import numpy as np
import matplotlib.pyplot as plt
# Matrix addition
matrix_sum = matrix1 + matrix2
print("\nMatrix Sum:\n", matrix_sum)
# Transpose of a matrix
matrix1_transpose = matrix1.T
print("\nTranspose of Matrix 1:\n", matrix1_transpose)
# Sample data
x = np.linspace(0, 10, 100) # 100 evenly spaced points from 0 to 10
y1 = np.sin(x)
y2 = np.cos(x)
# Create a plot
plt.figure(figsize=(10, 6)) # Set figure size
plt.figure(figsize=(8, 5))
plt.bar(categories, values, color='green')
plt.title('Bar Chart Example')
plt.xlabel('Categories')
plt.ylabel('Values')
plt.show()
plt.figure(figsize=(8, 5))
plt.scatter(x_scatter, y_scatter, color='purple', marker='o')
plt.title('Scatter Plot Example')
plt.xlabel('X')
plt.ylabel('Y')
plt.show()
1. Install Libraries:
Numpy Section:
Matplotlib Section:
Key Concepts:
● NumPy:
○ Provides efficient array operations for numerical computing.
○ np.array() creates NumPy arrays.
○ np.dot() performs matrix dot product.
○ .T gives the transpose of a matrix
○ np.mean() and np.sum() calculate mean and sum of array elements.
● Matplotlib:
○ Provides a powerful plotting library for creating various types of graphs.
○ plt.plot() creates line plots.
○ plt.bar() creates bar charts.
○ plt.scatter() creates scatter plots.
○ plt.title(), plt.xlabel(), plt.ylabel(), and plt.legend() add labels
and legends to plots.
○ plt.show() displays the plots.
NumPy (Numerical Python) is a fundamental library for numerical computing in Python. It provides
support for large, multi-dimensional arrays and matrices, along with a collection of high-level
mathematical functions to operate on these arrays.
Here's a breakdown of various NumPy functions, categorized for clarity, with examples:
● np.array(object, dtype=None): Creates a NumPy array from a list, tuple, or other array-like
object.
Python
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
print(arr) # Output: [1 2 3 4 5]
● np.empty(shape, dtype=float): Creates an array of the given shape and dtype, without
initializing elements to particular values.
Python
● np.arange([start,] stop[, step,], dtype=None): Returns evenly spaced values within a given
range.
Python
● np.reshape(a, newshape): Gives a new shape to an array without changing its data.
Python
arr = np.arange(6)
reshaped_arr = arr.reshape(2, 3)
print(reshaped_arr)
● np.transpose(a, axes=None) or a.T: Reverse or permute the axes of an array; returns the
modified array.
Python
● np.concatenate((a1, a2, ...), axis=0): Join a sequence of arrays along an existing axis.
Python
Python
arr = np.arange(9)
split_arr = np.split(arr, 3) # Split into 3 equal parts
print(split_arr)
Python
Python
3. Mathematical Functions:
Python
Python
diff_arr = np.subtract(arr2, arr1)
print(diff_arr) # Output: [3 3 3]
Python
Python
Python
Python
Python
Python
Python
Python
Python
Python
cos_arr = np.cos(arr)
print(cos_arr) # Output: [ 1. -1. -1.]
● np.reshape(a, newshape): Gives a new shape to an array without changing its data.
Python
arr = np.arange(6)
reshaped_arr = arr.reshape(2, 3)
print(reshaped_arr)
● np.resize(a, new_shape): Return a new array with the specified shape. If the new array is
larger than the original array, then the new array is filled with repeated copies of a. Note that
this behavior is different from a.resize() which modifies a in place
Python
Python
Python
Python
Python
Python
Python
Python
Python
● np.linalg.solve(a, b): Solve a linear matrix equation, or system of linear scalar equations.
Python
● np.random.rand(d0, d1, ..., dn): Create an array of the given shape and populate it with
random samples from a uniform distribution over [0, 1).
Python
rand_arr = np.random.rand(2, 3)
print(rand_arr)
● np.random.randn(d0, d1, ..., dn): Return a sample (or samples) from the "standard normal"
distribution.
Python
randn_arr = np.random.randn(2, 3)
print(randn_arr)
● np.random.randint(low, high=None, size=None, dtype=int): Return random integers from the
“discrete uniform” distribution of the specified dtype in the “half-open” interval [low, high).
Python
● np.array_equal(a1, a2): True if two arrays have the same shape and elements, False
otherwise.
Python
1. Creating a Class with method 2. Creating Objects of class 3. Accessing method using object
● Class Definition:
○ A class is like a blueprint for creating objects. It defines the attributes (data) and
methods (functions) that objects of that class will have.
○
○ In Python, you define a class using the class keyword.
○ The convention is to use CamelCase for class names (e.g., MyClass).
● Methods:
○ Methods are functions defined within a class. They operate on the objects of that
class.
○ The first parameter of a method is always self. self refers to the instance of the
object that the method is called on.
○ Methods define the behavior of objects.
● __init__ (Constructor):
● Object Creation:
○ An object is an instance of a class.
○ Creating an object is called instantiation.
○ You create an object by calling the class name as if it were a function.
● Method Invocation:
○ To call a method on an object, you use the dot notation (object.method()).
def bark(self):
"""Simulates the dog barking."""
return "Woof!"
def get_info(self):
"""Returns a string describing the dog."""
return f"{self.name} is a {self.breed} and is {self.age} years old."
Explanation:
1. Class Dog:
● Encapsulation: Bundling data (attributes) and methods that operate on the data within a
single unit (class).
● Abstraction: Hiding complex implementation details and showing only necessary information.
● Inheritance: Creating new classes (derived classes) from existing classes (base classes).
● Polymorphism: The ability of objects of different classes to respond to the same method call
in different ways.
The __init__ method, which is a special method in Python classes. It's the constructor, and it's
essential for initializing the attributes (data) of objects when they are created.
● def __init__(...):
○ def indicates that we are defining a function (in this case, a method).
○ __init__ is a special method name. In Python, methods with double underscores at
the beginning and end (dunder methods) have special meanings. __init__
specifically is the constructor.
● self:
○ The code inside the __init__ method typically assigns the parameter values to the
object's attributes.
○ Example:
■ self.name = name assigns the value of the name parameter to the name
attribute of the object.
■ self.breed = breed assigns the value of the breed parameter to the
breed attribute of the object.
■ self.age = age assigns the value of the age parameter to the age attribute
of the object.
Purpose of __init__:
● Initialization: The primary purpose of __init__ is to initialize the object's attributes when
the object is created.
● Setting Initial State: It allows you to set the initial state of an object, ensuring that it has the
necessary data to function correctly.
● Automatic Execution: Python automatically calls the __init__ method when you create an
object, so you don't have to call it explicitly.
Practical No. 21: Write a python program to demonstrate the use of constructors:
1. Default 2. Parameterized 3. Constructor Overloading
What is a Constructor?
○ You don't need to call the constructor explicitly. When you create an object using the
class name followed by parentheses (like my_object = MyClass()), Python
automatically calls the __init__ method.
3. Initialization of Attributes:
○The most common use of a constructor is to set the initial values of an object's
attributes.
○ Attributes are variables that store data associated with an object.
○ Inside the constructor, you use the self keyword to refer to the object itself and
assign values to its attributes.
4. self Parameter:
○Every method in a class definition, including the constructor, must have self as its
first parameter.
○ self is a reference to the instance (the object) that the method is called on.
○ When you create an object, Python automatically passes the object itself as the self
argument.
○ You use self to access and modify the object's attributes within the method.
5. Return Value:
○ Constructors in Python implicitly return None. You should not explicitly return any
value from the __init__ method.
● Default Constructor:
class Car:
def __init__(self, make="Unknown", model="Unknown", year=2000):
"""
Constructor for the Car class.
Args:
make (str, optional): The make of the car. Defaults to "Unknown".
model (str, optional): The model of the car. Defaults to Unknown".
year (int, optional): The year the car was made. Defaults to 2000.
"""
self.make = make
self.model = model
self.year = year
self.odometer = 0 # Initialize odometer to 0
class MyClass:
# 1. Default Constructor
def __init__(self):
"""Default constructor with no parameters."""
self.message = "Default Constructor Called"
print("Default Constructor Called")
# 2. Parameterized Constructor
def __init__(self, value):
"""Parameterized constructor with one parameter."""
self.value = value
print(f"Parameterized Constructor Called with value: {value}")
def display(self):
"""Displays the value or message."""
try:
print(f"Value: {self.value}")
except AttributeError:
print(self.message)
# Demonstration
# Trying to use the default constructor directly will lead to an error because
# the parameterized constructor overrides the default one.
# obj3 = MyClass() # This will cause a TypeError
def display(self):
"""Displays the values or message."""
try:
print(f"Value 1: {self.value1}, Value 2: {self.value2}")
except AttributeError:
try:
print(f"Value: {self.value}")
except AttributeError:
print(self.message)
obj5 = OverloadedClass(20)
obj5.display()
Concepts Demonstrated:
● 1. Default Constructor:
○ A constructor with no parameters. In Python, if you define a parameterized constructor,
the default constructor is implicitly overridden.
● 2. Parameterized Constructor:
○ A constructor with one or more parameters.
● 3. Constructor Overloading (Simulated):
○ Python does not support true constructor overloading like some other languages (e.g.,
C++ or Java).
○ However, you can simulate constructor overloading by using default arguments in a
single constructor.
○ By checking if the arguments are none, we can make the constructor act as multiple
constructors.
○ This allows you to create objects with different sets of arguments.
Key Points:
● In Python, if you define a parameterized constructor, you cannot create an object using the
default constructor (without arguments).
● The __init__ method is automatically called when an object is created.
● The try...except blocks in the display methods handle the case where the object might
not have a certain attribute (e.g., self.value).
● Constructor overloading in Python is generally simulated using default argument values and
conditional logic within a single __init__ method.
Practical No. 22: Implement a python program to demonstrate
1. Method Overloading 2. Method Overriding
Method Overloading and Method Overriding, two important aspects of object-oriented programming
(OOP).
1. Method Overloading
● Definition:
○ Method overloading is the ability of a class to have multiple methods with the same
name but different parameter lists (different number, types, or order of parameters).
○ The compiler or interpreter selects the correct method to call based on the arguments
passed during the method invocation.
● Purpose:
○ Method overloading provides a way to implement methods that perform similar actions
but can handle different types or amounts of input data.
○ It enhances code flexibility and readability by allowing you to use the same method
name for related operations.
● How it Works (in theory):
○ Python does not support method overloading in the traditional sense like some other
languages (e.g., C++, Java).
○ If you define multiple methods with the same name in a Python class, the last definition
will override any previous definitions.
○ However, we can achieve similar functionality using default arguments, variable-length
argument lists (*args, **kwargs), and conditional logic within a single method.
● Example (Simulation of Method Overloading in Python):
class Calculator:
def add(self, a, b=None, c=None):
"""
Simulates method overloading for addition.
"""
if b is None and c is None:
return a # Returns a if only one argument is provided
elif b is not None and c is None:
return a + b
elif b is not None and c is not None:
return a + b + c
else:
return 0 # Or handle this case as needed
calc = Calculator()
print(calc.add(5)) # Output: 5
print(calc.add(5, 10)) # Output: 15
print(calc.add(5, 10, 15)) # Output: 30
2. Method Overriding
● Definition:
○ The subclass defines a method with the same name and the same signature
(parameter list) as a method in its superclass.
○ When the method is called on an object of the subclass, Python's method resolution
order (MRO) ensures that the subclass's method is found and executed first.
● Method Overriding in Python:
○ Python supports method overriding directly. You simply define a method with the same
name in the subclass.
● Example:
class Animal:
def make_sound(self):
"""
Generic sound-making method.
"""
return "Generic animal sound"
class Dog(Animal):
def make_sound(self):
"""
Overrides the make_sound method for dogs.
"""
return "Woof!"
class Cat(Animal):
def make_sound(self):
"""
Overrides the make_sound method for cats.
"""
return "Meow!"
animal = Animal()
dog = Dog()
cat = Cat()
● Overloading:
○ Same method name, different parameter lists (within the same class).
○ Python "simulates" it using default arguments, etc.
● Overriding:
○ Same method name, same signature (in different classes related by inheritance).
○ Used for specialization in subclasses.
class Calculator:
def add(self, a, b=None, c=None):
"""
Simulates method overloading for addition.
"""
if b is None and c is None:
return a # Returns a if only one argument is provided
elif b is not None and c is None:
return a + b
elif b is not None and c is not None:
return a + b + c
else:
return 0 # Or handle this case as needed
# 2. Method Overriding
class Animal:
def __init__(self, name):
self.name = name
def make_sound(self):
"""
Generic sound-making method.
"""
return "Generic animal sound"
def get_info(self):
"""Returns information about the animal."""
return f"This animal is a {type(self).__name__} named {self.name}."
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # Call the superclass constructor
self.breed = breed
def make_sound(self):
"""
Overrides the make_sound method for dogs.
"""
return "Woof!"
def get_info(self):
"""Overrides get_info to include breed information"""
return f"{self.name} is a {self.breed} Dog."
class Cat(Animal):
def __init__(self, name, color):
super().__init__(name) # Call the superclass constructor
self.color = color
def make_sound(self):
"""
Overrides the make_sound method for cats.
"""
return "Meow!"
def get_info(self):
"""Overrides get_info to include color information"""
return f"{self.name} is a {self.color} Cat."
print("animal.make_sound():", animal.make_sound())
print("dog.make_sound():", dog.make_sound())
print("cat.make_sound():", cat.make_sound())
print(animal.get_info())
print(dog.get_info())
print(cat.get_info())
Data hiding is a fundamental concept in object-oriented programming (OOP) that refers to the
practice of restricting access to certain components of an object. It's about controlling the visibility of
an object's data (attributes) and methods.
The primary goal of data hiding is to protect the internal state of an object from unintended or
inappropriate external access. It's about saying, "These parts of the object are internal details; don't
mess with them directly."
● Access Modifiers: Many languages use access modifiers (also called visibility modifiers) to
control access to class members (attributes and methods). Common access modifiers include:
○ Public: Members declared as public are accessible from anywhere.
○ Private: Members declared as private are only accessible within the class itself.
○ Protected: Members declared as protected are accessible within the class itself and
its subclasses.
Python takes a slightly different approach to data hiding compared to languages like Java or C++. It
relies more on convention and a concept called "name mangling" rather than strict access modifiers.
● Naming Conventions:
○ Single Underscore Prefix (_): A single underscore prefix before an attribute or
method name (e.g., _my_attribute) is a convention that indicates to other
programmers that this member is intended for internal use. It's a signal that you
shouldn't access it directly from outside the class. However, Python doesn't prevent
you from doing so. It's more of a guideline.
○ Double Underscore Prefix (__): A double underscore prefix (e.g.,
__my_attribute) triggers name mangling. Python interpreter renames the attribute
to _ClassName__my_attribute. This makes it harder (but not impossible) to
access the attribute from outside the class. Name mangling is primarily intended to
avoid namespace clashes in inheritance.
Example in Python:
class MyClass:
def __init__(self):
self.public_attribute = "This is public"
self._internal_attribute = "This is internal (by convention)"
self.__private_attribute = "This is 'private' (name mangled)"
def public_method(self):
print(self.public_attribute)
print(self._internal_attribute)
print(self.__private_attribute)
def _internal_method(self):
print("This is an internal method")
obj = MyClass()
print(obj.public_attribute) # Accessible
print(obj._internal_attribute) # Accessible (but discouraged)
# You can access the name-mangled attribute like this (but it's generally not
recommended):
print(obj._MyClass__private_attribute)
In summary, data hiding in Python is a mechanism to control access to the internal state of objects.
It's achieved through naming conventions and name mangling, promoting encapsulation, abstraction,
modularity, and maintainability. While Python's approach is based more on convention than strict
enforcement, it's an important practice for writing well-structured and robust object-oriented code.
class BankAccount:
def __init__(self, account_number, balance):
self.account_number = account_number # Public attribute
self._balance = balance # Internal attribute (by convention)
self.__secret_pin = "1234" # Name-mangled attribute (simulating
private)
def get_balance(self):
return self._internal_check_balance()
# Accessing the name-mangled attribute using the mangled name (works, but
strongly discouraged)
print("Mangled pin access (strongly discouraged):",
account._BankAccount__secret_pin)
● Public Attribute:
○ account_number is a public attribute, accessible from anywhere.
● Internal Attribute (by Convention):
○ _balance is an internal attribute. The single underscore indicates that it's intended for
internal use.
○ While you can access it from outside the class, it's considered bad practice.
● Name-Mangled Attribute (Simulating Private):
○ __secret_pin is a name-mangled attribute. Python renames it internally to
_BankAccount__secret_pin.
○ This makes it harder to access from outside the class, but it's not truly private.
● Internal Method (by Convention):
○ _internal_check_balance() is an internal method, following the single
underscore convention.
● Name-Mangled Method:
○ __access_pin() is a name mangled method that can only be accessed by the
mangled name or by calling a public method that calls it.
● Public Interface:
○ deposit() and get_balance() provide a public interface for interacting with the
BankAccount object.
○ These methods control access to the internal data and ensure that operations are
performed correctly.
● Accessing Mangled Attributes:
○ The example shows how to access the name-mangled attribute using its mangled
name (account._BankAccount__secret_pin). This is strongly discouraged
because it breaks encapsulation.
● Authentication:
○ The authenticate_and_get_pin() method demonstrates how to use the name
mangled pin in a controlled manner.
Important Notes:
Inheritance is a fundamental concept in object-oriented programming (OOP) that allows you to create
new classes (called subclasses or derived classes) based on existing classes (called superclasses,
base classes, or parent classes). The subclass inherits the attributes and methods of the superclass,
which promotes code reuse and creates a hierarchical relationship between classes.
Key Concepts:
1. Defining a Subclass:
○ To create a subclass, you specify the superclass in parentheses after the subclass's
name in the class definition.
○ class Subclass(Superclass):
2. Inheriting Attributes and Methods:
○ The subclass automatically inherits all the attributes and methods of the superclass.
○ You can access these inherited members using the subclass's objects.
3. Overriding Methods:
○A subclass can provide its own implementation of a method that is already defined in
the superclass. This is called method overriding.
○ When you call an overridden method on an object of the subclass, the subclass's
version of the method is executed.
4. Adding New Attributes and Methods:
○ A subclass can add new attributes and methods that are specific to that subclass.
5. Calling Superclass Methods Using super():
○ The super() function allows you to call methods of the superclass from within the
subclass.
○ This is particularly useful when you want to extend the functionality of a superclass
method rather than completely replace it.
Example:
class Animal:
def __init__(self, name):
self.name = name
def make_sound(self):
return "Generic animal sound"
def get_name(self):
return self.name
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # Call the Animal constructor
self.breed = breed
def make_sound(self):
return "Woof!" # Override the Animal method
def get_breed(self):
return self.breed
# Creating objects
animal = Animal("Generic Animal")
dog = Dog("Buddy", "Golden Retriever")
# Accessing methods
print(animal.make_sound()) # Output: Generic animal sound
print(dog.make_sound()) # Output: Woof!
Explanation:
Benefits of Inheritance:
# 1. Single Inheritance
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "Generic animal sound"
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # Call the Animal constructor
self.breed = breed
def speak(self):
return "Woof!" # Override the Animal method
def get_breed(self):
return self.breed
# 2. Multiple Inheritance
class Swimmer:
def swim(self):
return "Swimming..."
class Walker:
def walk(self):
return "Walking..."
# 3. Multilevel Inheritance
class Vehicle:
def __init__(self, make, model):
self.make = make
self.model = model
def start(self):
return "Vehicle started"
class Car(Vehicle):
def __init__(self, make, model, num_doors):
super().__init__(make, model)
self.num_doors = num_doors
def drive(self):
return "Car is driving"
class SportsCar(Car):
def __init__(self, make, model, num_doors, top_speed):
super().__init__(make, model, num_doors)
self.top_speed = top_speed
def accelerate(self):
return "Sports car accelerating!"
Concepts Demonstrated:
● 1. Single Inheritance:
○ The Dog class inherits from the Animal class.
○ The Dog class overrides the speak() method and adds a get_breed() method.
● 2. Multiple Inheritance:
○ The Frog class inherits from Animal, Swimmer, and Walker.
○ The Frog class inherits and uses methods from all three parent classes.
● 3. Multilevel Inheritance:
○ The SportsCar class inherits from the Car class, which in turn inherits from the
Vehicle class.
○ This creates a chain of inheritance, where SportsCar inherits attributes and methods
from both Car and Vehicle.
○ The use of super() is demonstrated to call the constructor of the parent class.
Key Points:
● super() is used to call the constructor of the superclass, ensuring that the superclass's
attributes are initialized.
● Method overriding allows subclasses to provide their own implementations of methods defined
in superclasses.
● Multiple inheritance allows a class to inherit from multiple parent classes.
● Multilevel inheritance enables a class to inherit from a class that inherits from another class,
creating a hierarchy.
Practical No. 25: Implement Python program to perform following operations using panda
package:
1. Create Series from Array
2. Create Series from List
3. Access element of series
4. Create DataFrame using List or dictionary
Pandas is a powerful Python library used for data manipulation and analysis. It provides data
structures for efficiently storing and working with structured data, such as tables (similar to
spreadsheets or SQL tables). Here's a breakdown of the Pandas package and its key features:
● Series: A one-dimensional labeled array capable of holding any data type (integers, strings,
floating-point numbers, Python objects, etc.). You can think of it as a single column of a
spreadsheet.
● DataFrame: A two-dimensional labeled data structure with columns of potentially different data
types. It's like a spreadsheet or a SQL table, with rows and columns.
Key Functionality:
● Data Input/Output:
○ pd.read_csv(filepath_or_buffer, ...): Reads data from a CSV (Comma
Separated Values) file.
○ pd.read_excel(io, ...): Reads data from an Excel file.
○ pd.read_sql(sql, con, ...): Reads data from a SQL database.
○ df.to_csv(filepath_or_buffer, ...): Writes DataFrame to a CSV file.
○ df.to_excel(excel_writer, ...): Writes DataFrame to an Excel file.
○ df.to_sql(name, con, ...): Writes DataFrame to a SQL database.
● Data Selection/Indexing:
○ df[colname]: Selects a column by its label (name).
○ df[[col1, col2, ...]]: Selects multiple columns.
○ df.loc[row_label, col_label]: Accesses a single value by label.
○ df.iloc[row_position, col_position]: Accesses a single value by integer
position.
○ df.loc[start_row:end_row, start_col:end_col]: Selects rows and
columns by label.
○ df.iloc[start_row:end_row, start_col:end_col]: Selects rows and
columns by integer position.
○ Boolean indexing: Selects rows based on a condition (e.g., df[df['column'] >
value]).
● Data Manipulation:
○ df.head(n): Returns the first n rows.
○ df.tail(n): Returns the last n rows.
○ df.info(): Provides information about the DataFrame (data types, non-null
values, etc.).
○ df.describe(): Generates descriptive statistics (mean, std, min, max, etc.) for
numeric columns.
○ df.shape: Returns the dimensions (rows, columns) of the DataFrame.
○ df.dtypes: Returns the data types of each column.
○ df.sort_values(by, ...): Sorts the DataFrame by one or more columns.
○ df.drop(labels, axis, ...): Removes rows or columns.
○ df.fillna(value): Fills missing values.
○ df.dropna(...): Removes rows or columns with missing values.
○ df.apply(func, axis): Applies a function along an axis (rows or columns).
○ df.groupby(by, ...): Groups data based on one or more columns for
aggregation.
○ df.merge(right, how, on, ...): Joins two DataFrames based on a
common column.
○ df.concat(objs, axis, ...): Concatenates DataFrames along an axis.
○ df.pivot_table(values, index, columns, ...): Creates a pivot table.
● Data Cleaning:
○ Handling missing values (e.g., fillna(), dropna()).
○ Removing duplicates (e.g., df.drop_duplicates()).
○ Converting data types (e.g., df['column'].astype(dtype)).
○ Cleaning string data (e.g., using string methods like str.replace(),
str.lower()).
import pandas as pd
# Create a DataFrame
data = {'Name': ['Alice', 'Bob', 'Charlie', 'David'],
'Age': [25, 30, 28, 35],
'City': ['New York', 'Los Angeles', 'Chicago', 'Houston']}
df = pd.DataFrame(data)
# Select a column
print("\nSelected column 'Name':\n", df['Name'])
# Filter rows
print("\nPeople older than 29:\n", df[df['Age'] > 29])
import pandas as pd
import numpy as np
1. Install Pandas:
pip install pandas
● Series Creation:
○ pd.Series(data, index): Creating Series from NumPy arrays and Python
lists, with and without custom indices.
● Series Element Access:
○ Using square brackets `` for basic indexing.
○ .loc for label-based indexing (using index names).
○ .iloc for integer-based indexing (using numerical positions).
● DataFrame Creation:
○ pd.DataFrame(data, columns): Creating DataFrames from:
■ List of Lists
■ List of Dictionaries
■ Dictionary of Lists
Practical No. 26: Implement python program to load a CSV file into a Pandas DataFrame and
perform operations.
import pandas as pd
# Assuming you have a CSV file named 'data.csv' in the same directory
# You can replace 'data.csv' with the actual path to your CSV file.
try:
df = pd.read_csv('data.csv') # Read the CSV file into a DataFrame
print("CSV file loaded successfully!\n")
except FileNotFoundError:
print("Error: CSV file not found. Please make sure 'data.csv' exists in
the same directory.")
exit() # Exit the program if the file is not found
# Get information about the DataFrame (data types, non-null values, etc.)
print("\nDataFrame Information:\n", df.info())
# Remember to replace 'data.csv' with the actual name of your CSV file.
○ You'll need a CSV file to test this code. You can create a simple one like this:
Code snippet
Name,Age,City
Alice,25,New York
Bob,30,Los Angeles
Charlie,35,Chicago
David,28,Houston
○ Save this data as a file named data.csv in the same directory as your Python script.
2. Install Pandas:
● Loading CSV: pd.read_csv() is used to load data from a CSV file into a Pandas
DataFrame.
● Basic DataFrame Inspection:
○ df.head() and df.tail(): Displaying the first and last rows.
○ df.info(): Getting DataFrame information.
○ df.describe(): Descriptive statistics.
○ df.shape: DataFrame dimensions.
○ df.dtypes: Column data types.
● Data Selection:
○ df['column']: Selecting a column.
○ df[['col1', 'col2']]: Selecting multiple columns.
○ df.loc[row_label, col_label]: Accessing values by label.
○ df.iloc[row_position, col_position]: Accessing values by integer position.
○ Boolean indexing: Filtering rows based on a condition.
● Data Manipulation:
○ Calculating the mean of a column.
○ Sorting the DataFrame.
○ Adding a new column.
● Error Handling:
○ A try...except block is used to handle the FileNotFoundError in case the CSV
file is not found.
○ KeyError exceptions are handled when trying to access or operate on columns that
might not exist in the CSV.
Tkinter is the standard Python interface to the Tk GUI toolkit shipped with Python. It's a cross-platform
toolkit, meaning you can create GUI applications that run on Windows, macOS, and Linux with the
same code.
● Standard Library: Tkinter is part of the Python standard library, so you don't need to install
any additional packages.
●
● Simple and Easy to Learn: Tkinter is relatively easy to learn and use, especially for
beginners.
●
● Cross-Platform: Applications created with Tkinter can run on different operating systems
without significant modifications.
●
● Widgets: Tkinter provides a wide range of GUI elements called widgets, such as buttons,
labels, text boxes, menus, and more.
●
● Event-Driven Programming: Tkinter applications are event-driven, meaning they respond to
user actions (events) like button clicks or keyboard input.
●
● Layout Managers: Tkinter provides layout managers (like pack, grid, and place) to control
the arrangement of widgets within the window.
Core Components:
● tkinter Module: The main module that provides access to all Tkinter classes and functions.
● Tk Class: The top-level window of the application.
●
● Widgets:
○ Label: Displays text or images.
○ Button: Creates clickable buttons.
○ Entry: Creates single-line text input fields.
○ Text: Creates multi-line text input fields.
○ Frame: Creates container widgets to group other widgets.
○ Canvas: Provides a drawing surface.
○ Checkbutton: Creates checkboxes.
○ Radiobutton: Creates radio buttons.
○ Listbox: Creates lists of items.
○ Menu: Creates menus.
○ Messagebox: displays pop up message boxes.
○ And many more...
● Layout Managers:
○ pack(): Arranges widgets in simple layouts.
○
○ grid(): Arranges widgets in a grid (rows and columns).
○
○ place(): Arranges widgets at specific coordinates.
○
● Events:
○ Tkinter uses an event-driven model.
○ Events are user actions or system events (e.g., button clicks, key presses, window
resizing).
○ You can bind event handlers (functions) to events to respond to them.
○
● Variables:
○ Tkinter provides variable classes (like StringVar, IntVar, BooleanVar, and
DoubleVar) to manage widget data.
○ These variables are linked to widget properties, so changes to the variables are
reflected in the widgets, and vice versa.
○
Import tkinter:
Python
import tkinter as tk
Create widgets:
Python
label = tk.Label(window, text="Hello, Tkinter!")
button = tk.Button(window, text="Click Me")
Python
import tkinter as tk
window = tk.Tk()
window.title("Simple Tkinter Example")
def button_click():
label.config(text="Button Clicked!")
window.mainloop()
Advantages of Tkinter:
Disadvantages of Tkinter:
● Can have a "dated" look and feel compared to more modern GUI toolkits.
●
● May not be as powerful or feature-rich as some other GUI libraries.
Tkinter is a great starting point for learning GUI programming in Python. As you become more
experienced, you might explore other GUI toolkits like PyQt, Kivy, or wxPython, which offer more
advanced features and customization options.
Python
import tkinter as tk
Explanation:
○
This line imports the Tkinter library, which is the standard Python interface to the Tk
GUI toolkit.
○ as tk is an alias, making it easier to refer to Tkinter components (e.g., tk.Label
instead of tkinter.Label).
2. window = tk.Tk():
How to Run:
1. Save the code: Save the code as a .py file (e.g., tkinter_window.py).
2. Run the script: Open a terminal or command prompt, navigate to the directory where you
saved the file, and run python tkinter_window.py.
A simple window with the title "My Tkinter Window" will appear on your screen.