Chapter 16 Object Orientation
16.1 What is Object Orientation?
- An effective program often utilizes an object-oriented approach in its design. Therefore, most coding languages evolve as an object-oriented language.
- In OO design, systems consist of collaborating sets of well-defined objects. One object sends a message to another object to achieve some goal.
- The message is implemented as a function call, often referred to as a method. Therefore, methods are associated with specific objects and depend on the nature of the object as well.
## Examples of String object's methods
= text.upper()
newstring = text.lower()
newstring = text.split() newstring
- An object’s blueprint determines its structure. This blueprint is referred to as the class definition. When we create a new object from the object’s class definition, the object is an instance of the class and the process is called instantiation.
- In addition to methods, an object can also have attributes or properties that we can get and set. We can also determine whether to hide these attributes and make them available only through the methods (private attributes) or expose them to the outside world (public attributes).
16.2 Class Defition
- A Class definition is a template for a new object instance. While there are many pre-defined classes available in default Python modules, we can define our own class depending on the tasks at hand.
- In a class definition, usually we include:
- the mechanism and data required to create an new instance of the class (constructor method(s)),
- its attributes (both private and public attributes),
- the methods that can be used to set and get attributes or change the state ob the object (class methods).
# Define a class
class Employee(object):
"Employee Class"
# Constructor method
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.email = first + '.' + last + '@email.com'
self.pay = pay
# instance method
def fullname(self):
return '{} {}'.format(self.first, self.last)
= Employee('Alvin', 'Chen', 50000)
emp_1 = Employee('John', 'Doe', 60000)
emp_2
emp_1.fullname()
'Alvin Chen'
emp_2.fullname()
'John Doe'
16.3 Types of Methods
- Class Method: a method bound to the class and with
cls
as the first default argument - Static Method: a self-contained method bound to the class
- Instance Method: a method bound to the object instance of the class with
self
as the first default argument
class Employee(object):
= 0
num_of_emps = 1.04
raise_amt
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.email = first + '.' + last + '@email.com'
self.pay = pay
+= 1
Employee.num_of_emps
def fullname(self):
return '{} {}'.format(self.first, self.last)
def apply_raise(self):
self.pay = int(self.pay * self.raise_amt)
@classmethod
def set_raise_amt(cls, amount):
= amount
cls.raise_amt
@classmethod
def from_string(cls, emp_str):
= emp_str.split('-')
first, last, pay return cls(first, last, pay)
@staticmethod
def is_workday(day):
if day.weekday() == 5 or day.weekday() == 6:
return False
return True
= Employee('Corey', 'Schafer', 50000)
emp_1 = Employee('Test', 'Employee', 60000)
emp_2
1.05)
Employee.set_raise_amt(
print(Employee.raise_amt)
1.05
print(emp_1.raise_amt)
1.05
print(emp_2.raise_amt)
1.05
= 'John-Doe-70000'
emp_str_1 = 'Steve-Smith-30000'
emp_str_2 = 'Jane-Doe-90000'
emp_str_3
= emp_str_1.split('-')
first, last, pay
#new_emp_1 = Employee(first, last, pay)
= Employee.from_string(emp_str_1)
new_emp_1
print(new_emp_1.email)
John.Doe@email.com
print(new_emp_1.pay)
70000
import datetime
= datetime.date(2016, 7, 11)
my_date
print(Employee.is_workday(my_date))
True
16.4 Class Inheritance
- With the class definition, we can create as many instances of the class as needed.
- Moreover, with the class definition, we can create suborindate or superordinate classess based on the original class. These sub-classess have taxonomic relationships with the original super class.
- Extend the original class constructor methods using
super()
class Employee:
= 1.04
raise_amt
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.email = first + '.' + last + '@email.com'
self.pay = pay
def fullname(self):
return '{} {}'.format(self.first, self.last)
def apply_raise(self):
self.pay = int(self.pay * self.raise_amt)
class Developer(Employee):
= 1.10
raise_amt
def __init__(self, first, last, pay, prog_lang):
super().__init__(first, last, pay)
self.prog_lang = prog_lang
class Manager(Employee):
def __init__(self, first, last, pay, employees=None):
super().__init__(first, last, pay)
if employees is None:
self.employees = []
else:
self.employees = employees
def add_emp(self, emp):
if emp not in self.employees:
self.employees.append(emp)
def remove_emp(self, emp):
if emp in self.employees:
self.employees.remove(emp)
def print_emps(self):
for emp in self.employees:
print('-->', emp.fullname())
= Developer('Alvin', 'Chen', 50000, 'Python')
dev_1 = Developer('John', 'Doe', 60000, 'R')
dev_2
= Manager('Anne', 'Mary', 90000, [dev_1])
mgr_1
print(mgr_1.email)
Anne.Mary@email.com
mgr_1.add_emp(dev_2)
mgr_1.remove_emp(dev_2)
mgr_1.print_emps()
--> Alvin Chen
16.5 Special Methods
- Dunder methods (double-underscore)
- To avoid overloading the expressions in coding
class Employee:
= 1.04
raise_amt
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.email = first + '.' + last + '@email.com'
self.pay = pay
def fullname(self):
return '{} {}'.format(self.first, self.last)
def apply_raise(self):
self.pay = int(self.pay * self.raise_amt)
def __repr__(self):
return "Employee('{}', '{}', {})".format(self.first, self.last, self.pay)
def __str__(self):
return '{} - {}'.format(self.fullname(), self.email)
def __add__(self, other):
return self.pay + other.pay
def __len__(self):
return len(self.fullname())
= Employee('Corey', 'Schafer', 50000)
emp_1 = Employee('Test', 'Employee', 60000)
emp_2
# print(emp_1 + emp_2)
print(len(emp_1))
13
16.6 Property Decorator
@property
: make a method function like attribute-accessing@NAME.setter
: make a method function like class-attribute assigning@NAME.deleter
: make a method function like class-attribute deleting
class Employee:
def __init__(self, first, last):
self.first = first
self.last = last
@property
def email(self):
return '{}.{}@email.com'.format(self.first, self.last)
@property
def fullname(self):
return '{} {}'.format(self.first, self.last)
@fullname.setter
def fullname(self, name):
= name.split(' ')
first, last self.first = first
self.last = last
@fullname.deleter
def fullname(self):
print('Delete Name!')
self.first = None
self.last = None
= Employee('John', 'Smith')
emp_1 = "Corey Schafer"
emp_1.fullname
print(emp_1.first)
Corey
print(emp_1.email)
Corey.Schafer@email.com
print(emp_1.fullname)
Corey Schafer
del emp_1.fullname
Delete Name!
16.7 Checking Functions
isinstance()
: Check an instance’s typeissubclass()
: Check class inheritance
16.8 Name Mangling
__NAME
: Any identifier of this form within the class is textually replaced with_classname__NAME
, whereclassname
is the current class name, with leading underscore(s) stripped.- This is for the purpose of creating private variables to the class.
16.9 Reference
- This notebook is based on Corey Schafer’s OOP Tutorial