Classes
Contents
Classes#
BB1000 Programming in Python
layout: false
Variables and Functions#
DATA: Variables
str1 = "Hello World!"
str2 = "Python Programming"
lst = ['physics', 'chemistry', 1997, 2000]
Actions: Functions
def printinfo(name, age):
print("Name" , name)
print("Age", age)
##Simple program

Objects and Classes#

##Objects and Classes
Procedure Oriented Programming#
functions and variables used to make program
suitable for small/medium programs
Object Oriented Programming#
objects used to make program
suitable for large programs
Everything in Python is an object, and almost everything has attributes (data) and methods (functions for manipulating data)
##Objects and Classes
Class - blueprint for creation of an object
class Person:
def __init__(self, given_name, surname):
self.given_name = given_name
self.surname = surname
def __str__(self):
return f"Person: {self.given_name} {self.surname}"
Class definition in Python#
class Name:
...
##Most important special method is a constuctor
def __init__(self, <list of parameters>):
...
##Objects and classes
###Ordinary class methods are defined as
def name_of_method(self, <list of paramters>):
...
###self is passed to all class methods and has the following meaning
In the constructor init refers to newly created object
In ordinary class methods it refers to the object for this method is called
Note: the __init__
method is often called a constructor, in analogy with
other OO languages, but the object has already been constructed entring the
function and is refered to with by the self
variable. Initializer would be a
more correct description
##Objects and Classes
Using objects in a program#
creating an instance of an object in a program
p = Person("Adam", "Smith")
accessing instance attributes in a program
p.given_name = 'John'
calling instance methods in a program
p.display_person()
Instance attributes vs Class attributes#
class Person:
number = 0 # class attribute
def __init__(self, given_name, surname):
self.given_name = given_name # instance attribute
self.surname = surname # instance attribute
Person.number += 1
def __str__(self):
return f"Person: {self.given_name} {self.surname}"
class attributes are shared by instances
instance attributes are unique to each instance
Data encapsulation in object oriented programming#
Public attributes can be freely used in side or outside of a class definition
self.name = value #Public attribute
Protected attributes should not be used outside of the class definition unless inside of a subclass definition
self._value = value # Protected attribute
Private atributes are inaccessible and invisible. It’s is neihter possible to read nor write to those attribtes, except inside of the class definition itself
self.__name = value #Private attribute
Special methods and overloading#
constructor
p = ClassName() # after creation calls p.__init__()
official string representation
repr(p) # calls p.__repr__()
informal string representation
str(p) # calls p.__str__()
getting attribute
p.attr # calls p._getattribute__('attr')
setting attribute
p.attr = value # calls p._setattribute__('attr', value)
getting list of attributes
dir(p) # calls x.__dir__()
overloading binary operators
p._add__(self, other) # addition, +
p._sub__(self, other) # subtraction, -
p._mul__(self, other) # multiplication, *
p._truediv__(self, other) # division, /
p._floordiv__(self, other) # floor division, //
Class inheritance#
Making derived class from base class:
class DerivedClassName(BaseClass): #inheriting from one base class
...
class DerivedClassName(BaseClass1, BaseClass2): #inheriting from multiple base classes
...
All methods ar virutal, i.e. overriding of methods is an intrinsic property of Python
Private attributes are not inherited
Relationship between derived ans base classes
issubclass(DerivedClass, BaseClass) #True or False
Relationship between instance and class
isinstance(Object, Class) # True or False
###Simple example of parent (base) and child (derived) classes
class Parent:
def __init__(self):
print("Base constructor")
def base_method(self):
print('Calling base method')
class Child(Parent):
def __init__(self):
print("Derived constructor")
def derived_method(self):
print('Calling derived method')
>>> c = Child()
Derived constructor
>>> c.base_method()
Calling base method
>>> c.derived_method()
Calling derived method
###When to use inheritance?
to avoid replication of code (same attributes and methods in different classes)
to take advantages of existing Python classes
when similar if statements are repeated throughout code
import moduleName
class DerivedClass(moduleName.BaseClass):
...
# override/add any functions here.
###Example employee class
class Person:
def __init__(self, given_name, surname):
self.given_name = given_name # instance attribute
self.surname = surname # instance attribute
def get_person(self):
return "Person : " + self.given_name + " " + self.surname
class Employee(Person):
def __init__(self, given_name, surname, salary):
super().__init__(given_name, surname)
self.salary = salary
def get_employee(self):
return self.get_person() + ", salary: " + str(self.salary)
>>> e = Employee('John', 'Doe', 29500)
>>> print(e.get_employee())
Person : John Doe, salary: 29500
###Replacing repeated if-statements with inheritance
def action(animal, name):
print(name, 'is a', animal)
if animal == 'Cat':
print(name, "says 'Meow'!")
elif animal == 'Dog':
print(name, "says 'Bow-wow!'")
else:
print("Don't know what", name, "sounds like")
if animal == 'Cat':
print(name, "chases mouse")
elif animal == 'Dog':
print(name, "chases cat")
else:
print("Don't know what", name, "chases")
Consider adding more animals and more behaviours - this pattern becomes difficult to maintain in larger codes
>>> action('Cat', 'Felix')
Felix is a Cat
Felix says 'Meow'!
Felix chases mouse
class Animal:
def __init__(self, name):
self.name = name
def action(self):
print(self.name, 'is a', self.__class__.__name__)
self.make_sound()
self.chase()
def make_sound(self):
print("Don't know what", self.name, "sounds like")
def chase(self):
print("Don't know what", self.name, "chases")
class Dog(Animal):
def make_sound(self):
print(self.name, "says 'Bow-wow!'")
def chase(self):
print(self.name, "chases cat")
class Cat(Animal):
def make_sound(self):
print(self.name, "says 'Meow'!")
def chase(self):
print(self.name, "chases mouse")
>>> Cat('Felix').action()
Felix is a Cat
Felix says 'Meow'!
Felix chases mouse
Class diagrams#
Are often used to illustrate dependencies between classes

each class is represented by a box
each box is divided name, attributes, methods
arrows indicate inheritance relationships
Static methods#
Static methods are ordinary functions, living in the class namespace. They
might as well be defined outside the class, except that they are now called
with a class name prefix. They do not depend on an instance, and do not have a
self
parameter.
Static methods are defined with the @staticmethod
decorator
class A:
def instance_method(self):
print("In instance_method")
@staticmethod
def static_method():
print("In static method")
>>> A().instance_method()
In instance_method
>>> A.static_method()
In static method
Class methods#
Class methods are often used as alternative constructors
class Dog:
def __init__(self, breed, name):
self.breed = breed
@classmethod
def snoopy(cls):
return cls('Beagle', 'Snoopy')
dog = Dog.snoopy()
print(dog.breed, dog.name)
Few practical tricks#
Use separate file to describe a class and import it into the main program
If you want to add some code to the class file, which is not definition of the class, use the following syntax
if __name__ == "__main__":
...
...