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

P 3 Python 1

Uploaded by

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

P 3 Python 1

Uploaded by

Hrudhya Haridas
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 65

(Object Oriented

Programming)
• Python Classes/Objects
• Python is an object oriented programming language.
• Almost everything in Python is an object, with its properties and
methods.
• A Class is like an object constructor, or a "blueprint" for creating
objects.
• Create a Class
• To create a class, use the keyword class:

• Example
• Create a class named MyClass, with a property named x:

• class MyClass:
• x=5
• Create an object named p1, and print the value of x:
• p1 = MyClass()
print(p1.x)
The __init__() Function
• The examples above are classes and objects in their simplest form, and
are not really useful in real life applications.
• To understand the meaning of classes we have to understand the built-in
__init__() function.
• All classes have a function called __init__(), which is always executed
when the class is being initiated.
• Use the __init__() function to assign values to object properties, or other
operations that are necessary to do when the object is being created:
• The __init__() function is called automatically every time the class is
being used to create a new object.
• Create a class named Person, use the __init__() function to assign
values for name and age:
• class Person:
def __init__(self, name, age):
self.name = name
self.age = age

p1 = Person("John", 36)

print(p1.name)
print(p1.age)
The __str__() Function
• The __str__() function controls what should be returned when the
class object is represented as a string.
• If the __str__() function is not set, the string representation of the
object is returned:
• The string representation of an object WITH the __str__() function:
• class Person:
def __init__(self, name, age):
self.name = name
self.age = age

def __str__(self):
return f"{self.name}({self.age})"

p1 = Person("John", 36)

print(p1)
Object Methods

• Objects can also contain methods. Methods in objects are functions that belong to
the object.
• Insert a function that prints a greeting, and execute it on the p1 object:
• class Person:
def __init__(self, name, age):
self.name = name
self.age = age

def myfunc(self):
print("Hello my name is " + self.name)

p1 = Person("John", 36)
p1.myfunc()
The self Parameter

The self parameter is a reference to the current


instance of the class, and is used to access variables
that belongs to the class.
It does not have to be named self , you can call it
whatever you like, but it has to be the first
parameter of any function in the class:
• Modify Object Properties
• Set the age of p1 to 40:
• p1.age = 40
• Delete Object Properties
• Delete the age property from the p1 object:
• del p1.age
• Delete Objects
• Delete the p1 object:
• del p1
• The pass Statement
• class definitions cannot be empty, but if you for some reason have a
class definition with no content
• class Person:
pass
Instance variables
• In Python, instance variables are variables that are defined inside a
class and belong to an instance (or object) of that class. Each object
created from a class can have its own distinct set of instance
variables. These variables are used to store data that is unique to
each object.
• Characteristics of Instance Variables:
• Instance variables are defined in the __init__() method (the
constructor), or any other method, using self.
• They are tied to an instance of the class, not to the class itself.
• Each instance (object) has its own copy of the instance variables.
• Difference from Class Variables:
• Instance Variables: Each object has its own copy, and changes to one
instance’s variables do not affect others.
• Class Variables: Shared across all instances of a class, and changes to
a class variable affect all instances.
constructor
• A constructor in Python is a special method that is automatically
called when a new object (instance) of a class is created. It is used to
initialize the object’s properties (instance variables). In Python, the
constructor method is called __init__().
Key Points about Constructors:
• The constructor method is always named __init__().
• It is invoked automatically when you create an instance of the class.
• It can take arguments to initialize the object's attributes.
• It ensures that the object starts with a valid initial state.
Basic syntax
• class ClassName:
def __init__(self, parameters):
# Initialize instance variables
self.variable1 = parameters1
self.variable2 = parameters2
• class Car:
# Constructor method
def __init__(self, brand, model, year):
self.brand = brand # Instance variable
self.model = model # Instance variable
self.year = year # Instance variable
Constructor with Default Values
• A constructor can also have default values for parameters. This allows
you to create an object without providing all the arguments.
class Car:
def __init__(self, brand="Unknown", model="Unknown", year=0):
self.brand = brand
self.model = model
self.year = year

def display_info(self):
print(f"Brand: {self.brand}, Model: {self.model}, Year: {self.year}")

# Creating objects with default values


car1 = Car() # Default values will be used
car2 = Car("Honda", "Civic", 2022)

car1.display_info() # Output: Brand: Unknown, Model: Unknown, Year: 0


car2.display_info() # Output: Brand: Honda, Model: Civic, Year: 2022
Constructor overloading
class Employee:
def __init__(self, name, age=0, department=None):
self.name = name
self.age = age
self.department = department

def display_info(self):
print(f"Name: {self.name}, Age: {self.age}, Department: {self.department}")

# Using constructor with different arguments


employee1 = Employee("Alice")
employee2 = Employee("Bob", 30)
employee3 = Employee("Charlie", 28, "HR")

employee1.display_info() # Output: Name: Alice, Age: 0, Department: None


employee2.display_info() # Output: Name: Bob, Age: 30, Department: None
employee3.display_info() # Output: Name: Charlie, Age: 28, Department: HR
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

# Alternative constructor using class method


@classmethod
def from_birth_year(cls, name, birth_year):
return cls(name, 2024 - birth_year)

def display_info(self):
print(f"Name: {self.name}, Age: {self.age}")

# Creating an object using the primary constructor


person1 = Person("Alice", 25)

# Creating an object using the alternative constructor


person2 = Person.from_birth_year("Bob", 1995)

person1.display_info() # Output: Name: Alice, Age: 25


person2.display_info() # Output: Name: Bob, Age: 29
Accessors
• Accessors (also known as getters) are methods used to retrieve or
access the value of an object's private or protected instance variables
in Python. They help encapsulate data, ensuring that internal
attributes are accessed only through specific methods rather than
directly.
class Student:
def __init__(self, name, age):
self.__name = name # Private instance variable
self.__age = age # Private instance variable

# Accessor (getter) method for name


def get_name(self):
return self.__name

# Accessor (getter) method for age


def get_age(self):
return self.__age

# Creating an object of the Student class


student1 = Student("Alice", 20)

# Accessing private instance variables using accessor methods


print(student1.get_name()) # Output: Alice
print(student1.get_age()) # Output: 20
• Explanation:
• Private Variables: The variables __name and __age are private
because of the double underscore prefix __. These variables cannot
be accessed directly from outside the class (e.g., student1.__name
would raise an error)
• .Accessors: The methods get_name() and get_age() are the accessor
methods (or getters) that allow us to retrieve the values of __name
and __age from outside the class, providing controlled access to these
private variables.
• Why Use Accessors?
• Encapsulation: By using accessors, you protect the internal state of an
object and ensure that data is accessed in a controlled way.
• Data Validation: Accessors give you the flexibility to add logic when
retrieving data. You could, for instance, filter, format, or validate data
before returning it.
• Read-Only Access: In some cases, you might want to allow read-only
access to certain properties of a class, and accessors provide this
functionality.
Example of an Accessor with Data
Validation:
class Employee:
def __init__(self, name, salary):
self.__name = name
self.__salary = salary

# Accessor with validation for salary


def get_salary(self):
if self.__salary < 0:
return "Salary cannot be negative"
return self.__salary

employee1 = Employee("John", 50000)


employee2 = Employee("Jane", -1000)

print(employee1.get_salary()) # Output: 50000


print(employee2.get_salary()) # Output: Salary cannot be negative
• Pythonic Way to Use Accessors: Properties
• Instead of using explicit getter methods, Python has a more
"pythonic" way of implementing accessors through the @property
decorator. This allows you to define methods that behave like
attributes but can still encapsulate data.
class Student:
def __init__(self, name, age):
self.__name = name # Private instance variable
self.__age = age # Private instance variable

# Using @property for the name


@property
def name(self):
return self.__name

# Using @property for the age


@property
def age(self):
return self.__age

# Creating an object of the Student class


student1 = Student("Alice", 20)

# Accessing private instance variables as if they were public


attributes
print(student1.name) # Output: Alice
print(student1.age) # Output: 20
Mutators
• Mutators (also known as setters) are methods used in object-oriented
programming to modify or update the value of an object's private or
protected instance variables. Mutators ensure controlled modification
of data, often incorporating validation or transformation logic to
maintain the integrity of the object's state.
class Person:
def __init__(self, name, age):
self.__name = name # Private attribute
self.__age = age # Private attribute
# Accessor (getter) for age
def get_age(self):
return self.__age
# Mutator (setter) for age with validation
def set_age(self, age):
if age > 0:
self.__age = age
else:
print("Invalid age. Age must be positive.")
# Creating an object of the Person class
person = Person("John", 25)
# Accessing the age using the accessor
print("Current age:", person.get_age()) # Output: Current age: 25
# Modifying the age using the mutator
person.set_age(30)
print("Updated age:", person.get_age()) # Output: Updated age: 30
# Trying to set an invalid age
person.set_age(-5) # Output: Invalid age. Age must be positive.
• Explanation:
• The Person class has a private attribute __age.
• The set_age() method is a mutator that allows you to change the age,
but it includes validation to ensure that the age is positive.
• When you try to set an invalid age (like -5), the mutator method
prevents the change and prints a warning message.
• Mutators with @property Decorator (Pythonic Way):
• Python provides a more elegant and "pythonic" way to implement
mutators using the @property decorator along with the
@<property_name>.setter decorator.
• This allows you to treat methods as attributes, providing both getter
and setter functionality without needing explicit method calls.
class Person:
def __init__(self, age):
self.__age = age # Private instance variable

@property
def age(self):
return self.__age
# Property setter for modifying the age (mutator)
@age.setter
def age(self, age):
if age > 0:
self.__age = age
else:
print("Invalid age. Age must be positive.")
# Creating an object of the Person class
person = Person(25)
print("Current age:", person.age)
# Modifying the age using the property setter
person.age = 30
print("Updated age:", person.age) # Output: Updated age: 30

# Trying to set an invalid age


person.age = -5 # Output: Invalid age. Age must be positive.
• @property: This decorator creates a getter, allowing you to access age
like a normal attribute (person.age).
• @age.setter: This decorator creates the setter (mutator) for age,
allowing controlled modification with validation. If the age is negative,
it shows an error message.
Python Inheritance

• Inheritance allows us to define a class that inherits all the methods


and properties from another class.
• Parent class is the class being inherited from, also called base class.
• Child class is the class that inherits from another class, also called
derived class.
• Create a Parent Class
• Any class can be a parent class, so the syntax is the same as creating any other
class:
• Create a Child Class
• To create a class that inherits the functionality from another class, send the
parent class as a parameter when creating the child class:
• Example
• Create a class named Student, which will inherit the properties and methods from
the Person class:
• class Student(Person):
pass
• Now the Student class has the same properties and methods as the
Person class.
• Example
• Use the Student class to create an object, and then execute the
printname method:
x = Student("Mike", "Olsen")
x.printname()
Add the __init__() Function
• Add the __init__() function to the Student class:

• class Student(Person):
• def __init__(self, fname, lname):
• #add properties etc.
• The child's __init__() function overrides the inheritance of the
parent's __init__() function.
• To keep the inheritance of the parent's __init__() function, add a call
to the parent's __init__() function:

• Example
class Student(Person):
def __init__(self, fname, lname):
Person.__init__(self, fname, lname)
• Use the super() Function
• Python also has a super() function that will make the child class inherit
all the methods and properties from its parent:
• By using the super() function, you do not have to use the name of the
parent element, it will automatically inherit the methods and properties
from its parent.
• Example
class Student(Person):
def __init__(self, fname, lname):
super().__init__(fname, lname)
• Add Properties
• Example
• Add a property called graduationyear to the Student class:

class Student(Person):
def __init__(self, fname, lname):
super().__init__(fname, lname)
self.graduationyear = 2019
• Add Method

• Add a method called welcome to the Student class:

class Student(Person):
def __init__(self, fname, lname, year):
super().__init__(fname, lname)
self.graduationyear = year

def welcome(self):
print("Welcome", self.firstname, self.lastname, "to the class of", self.graduationyear)
• If you add a method in the child class with the same name as a
function in the parent class, the inheritance of the parent method will
be overridden.
• Polymorphism in Python refers to the ability to define methods that are
common across multiple classes, allowing different objects to respond to
the same method in their own way. Polymorphism is a core concept in
object-oriented programming (OOP) and allows code reusability and
flexibility.
• Types of Polymorphism:
• Compile-time polymorphism (Method Overloading): Not directly
supported in Python (handled using default arguments).
• Runtime polymorphism (Method Overriding): Achieved by defining
methods with the same name in different classes, and Python uses the
method that belongs to the object type at runtime.
Python Polymorphism
• The word "polymorphism" means "many forms", and in programming
it refers to methods/functions/operators with the same name that
can be executed on many objects or classes
• Function Polymorphism
• An example of a Python function that can be used on different objects
is the len() function.
# len() works on both strings and lists
print(len("Hello")) # Output: 5
print(len([1, 2, 3, 4])) # Output: 4
Example of Polymorphism using
Method Overriding:
• class Car:
def __init__(self, brand, model):
self.brand = brand
self.model = model

def move(self):
print("Drive!")

class Boat:
def __init__(self, brand, model):
self.brand = brand
self.model = model

def move(self):
print("Sail!")

class Plane:
def __init__(self, brand, model):
self.brand = brand
self.model = model

def move(self):
print("Fly!")

car1 = Car("Ford", "Mustang") #Create a Car class


boat1 = Boat("Ibiza", "Touring 20") #Create a Boat class
plane1 = Plane("Boeing", "747") #Create a Plane class

for x in (car1, boat1, plane1):


x.move()
Abstract Classes in Python
• An abstract class is a class that cannot be instantiated and is designed to
be subclassed.
• It can contain one or more abstract methods, which are methods
declared but contain no implementation.
• Subclasses of an abstract class must implement these abstract methods.
• In Python, abstract classes are implemented using the abc (Abstract Base
Class) module.
• An abstract class serves as a blueprint for other classes.
• When a subclass of an abstract class does not implement all abstract
methods, it will also be considered abstract and cannot be instantiated
• Key Points:
• An abstract class cannot be instantiated.
• Subclasses must implement abstract methods.
• Abstract classes are defined using the ABC (Abstract Base Class) from
the abc module.
• Abstract methods are defined using the @abstractmethod decorator.
from abc import ABC, abstractmethod

# Abstract class
class Animal(ABC):
@abstractmethod
def make_sound(self):
"""Abstract method: must be implemented in subclasses."""
pass

def sleep(self):
"""Concrete method: common to all animals."""
print("This animal is sleeping.")

# Subclass Dog must implement the abstract method


class Dog(Animal):
def make_sound(self):
return "Woof!"

# Subclass Cat must implement the abstract method


class Cat(Animal):
def make_sound(self):
return "Meow!"
# Trying to instantiate the abstract class will raise an error
# animal = Animal() # TypeError: Can't instantiate abstract class
Animal

# Instantiating the subclasses and using their methods


dog = Dog()
cat = Cat()

print(dog.make_sound()) # Output: Woof!


print(cat.make_sound()) # Output: Meow!

dog.sleep() # Output: This animal is sleeping.


cat.sleep() # Output: This animal is sleeping.
• Explanation:
• Abstract Class Animal:The Animal class is marked as abstract by
inheriting from ABC.
• It has an abstract method make_sound(), which means any subclass
of Animal must implement this method.
• It also has a concrete method sleep(), which is inherited and can be
used directly by any subclass.
• Concrete Classes (Dog, Cat):Both Dog and Cat classes inherit from the
Animal abstract class.
• They must implement the make_sound() method since it is an
abstract method in the parent class.
• If they do not implement it, they cannot be instantiated.
• Behavior:You cannot create an instance of Animal directly because it
contains an abstract method.
• You can create instances of the Dog and Cat classes because they
provide implementations of the abstract method make_sound().
• Benefits of Abstract Classes:
• Enforces a common interface: Abstract classes ensure that all
subclasses share a common interface (e.g., make_sound()), promoting
consistency across related classes.
• Code reuse: Concrete methods in an abstract class can be inherited
by subclasses, reducing code duplication (like the sleep() method in
the example).
• Extensibility: Abstract classes can be extended by new subclasses,
which must implement the required abstract methods.
Exception Handling

• When an error occurs, or exception as we call it, Python will normally


stop and generate an error message.

• These exceptions can be handled using the try statement:


Python Try Except

• The try block lets you test a block of code for errors.

• The except block lets you handle the error.

• The else block lets you execute code when there is no error.

• The finally block lets you execute code, regardless of the result of the
try- and except blocks.
• Example
• The try block will generate an exception, because x is not defined:

try:
print(x)
except:
print("An exception occurred")
Many Exceptions
• You can define as many exception blocks as you want, e.g. if you want
to execute a special block of code for a special kind of error:
Else
• You can use the else keyword to define a block of code to be executed if no
errors were raised:
• Example
• In this example, the try block does not generate any error:
try:
print("Hello")
except:
print("Something went wrong")
else:
print("Nothing went wrong")
Finally

• The finally block, if specified, will be executed regardless if the try


block raises an error or not.
• try:
print(x)
except:
print("Something went wrong")
finally:
print("The 'try except' is finished")
Raise an exception

• As a Python developer you can choose to throw an exception if a


condition occurs.
• To throw (or raise) an exception, use the raise keyword.
• Raise an error and stop the program if x is lower than 0:
• x = -1

if x < 0:
raise Exception("Sorry, no numbers below zero")
The raise keyword is used to raise an exception.

You can define what kind of error to raise, and the text to print to the
user.

x = "hello"

if not type(x) is int:


raise TypeError("Only integers are allowed")

You might also like