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
newstring = text.upper()
newstring = text.lower()
newstring = text.split()
- 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)
'Alvin Chen'
'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):
num_of_emps = 0
raise_amt = 1.04
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.email = first + '.' + last + '@email.com'
self.pay = pay
Employee.num_of_emps += 1
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):
cls.raise_amt = amount
@classmethod
def from_string(cls, emp_str):
first, last, pay = emp_str.split('-')
return cls(first, last, pay)
@staticmethod
def is_workday(day):
if day.weekday() == 5 or day.weekday() == 6:
return False
return True
emp_1 = Employee('Corey', 'Schafer', 50000)
emp_2 = Employee('Test', 'Employee', 60000)
Employee.set_raise_amt(1.05)
print(Employee.raise_amt)
1.05
1.05
1.05
emp_str_1 = 'John-Doe-70000'
emp_str_2 = 'Steve-Smith-30000'
emp_str_3 = 'Jane-Doe-90000'
first, last, pay = emp_str_1.split('-')
#new_emp_1 = Employee(first, last, pay)
new_emp_1 = Employee.from_string(emp_str_1)
print(new_emp_1.email)
John.Doe@email.com
70000
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:
raise_amt = 1.04
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):
raise_amt = 1.10
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())
dev_1 = Developer('Alvin', 'Chen', 50000, 'Python')
dev_2 = Developer('John', 'Doe', 60000, 'R')
mgr_1 = Manager('Anne', 'Mary', 90000, [dev_1])
print(mgr_1.email)
Anne.Mary@email.com
--> Alvin Chen
16.5 Special Methods
- Dunder methods (double-underscore)
- To avoid overloading the expressions in coding
class Employee:
raise_amt = 1.04
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())
emp_1 = Employee('Corey', 'Schafer', 50000)
emp_2 = Employee('Test', 'Employee', 60000)
# 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):
first, last = name.split(' ')
self.first = first
self.last = last
@fullname.deleter
def fullname(self):
print('Delete Name!')
self.first = None
self.last = None
emp_1 = Employee('John', 'Smith')
emp_1.fullname = "Corey Schafer"
print(emp_1.first)
Corey
Corey.Schafer@email.com
Corey Schafer
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