You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

349 lines
11 KiB
Python

# To create a class, the "class" keyword is used along with a class name that starts with an uppercase letter.
# SYNTAX: class ClassName():
class SampleClass():
# The properties that all SampleClass objects must have are defined in a method called __init__.
# Any number of parameters can be passed to __init__(), but the first parameter should always be self.
# When a SampleClass instance is created, that instance is automatically passed to the self parameter.
def __init__(self, year):
self.year = year
# Methods are functions defined inside a class.
def show_year(self):
print(f'The year is: {self.year}')
# Creating an instance of SampleClass by calling the class and passing the required argument
myObj = SampleClass(2020)
# To access properties and call methods of an object instance, use dot notation
print(myObj.year)
# Result: 2020
myObj.show_year()
# Result: The year is: 2020
# [SECTION] Fundamentals of OOP
# There are four main fundamental principles in OOP
# Encapsulation
# Inheritance
# Polymorphism
# Abstraction
# [SECTION] Encapsulation
# Encapsulation is a mechanism of wrapping the attributes and the methods that act on them together as a single unit.
# In encapsulation, the attributes of a class are hidden from other classes and can be accessed only through the methods of the current class.
# Therefore, it is also known as data hiding.
# To achieve encapsulation:
# Declare the attributes of a class.
# Provide getter and setter methods to view and modify the attribute values.
# Why use encapsulation?
# The fields of a class can be made read-only or write-only.
# A class can have full control over what is stored in its fields.
class Person():
def __init__(self):
# The underscore prefix is a convention that signals: "Be careful with this attribute, it's intended for internal use within the class."
# Protected attribute: _name
self._name = "John Doe"
# Mini Exercise solution
self._age = 20
# setter method
def set_name(self, name):
self._name = name
# getter method
def get_name(self):
print(f'Name of Person: {self._name}')
# Mini Exercise solution
# setter method set_age
def set_age(self, age):
self._age = age
# getter method get_age
def get_age(self):
print(f'Age of Person: {self._age}')
# Creating an instance of the Person class
person1 = Person()
print("Encapsulation:")
# getter
person1.get_name()
# Result: Name of Person: John Doe
# setter
person1.set_name("Bob Doe")
person1.get_name()
# Result: Name of Person: Bob Doe
# Mini Exercise 1:
# Add another protected attribute called "age"
# Create the necessary getter and setter methods
# Output: "Age of Person: <age>"
# Mini Exercise solution
person1.set_age(20)
person1.get_age()
# Result: Age of Person: 20
# [SECTION] Inheritance
# Inheritance is the transfer of characteristics from one class (the parent) to other classes (the children) derived from it.
# For example, an employee is a person with additional attributes and methods.
# To create a subclass (inherited class), specify the parent class in the class definition.
# SYNTAX: class ChildClassName(ParentClassName):
class Employee(Person):
def __init__(self, employeeId):
super().__init__()
self._employeeId = employeeId
# getter method
def get_employeeId(self):
print(f"The Employee ID is {self._employeeId}")
# setter method
def set_employeeId(self, employeeId):
self._employeeId = employeeId
# custom methods
# Custom methods are methods you create in a class to do specific tasks that aren't built-in or inherited.
def get_details(self):
print(f"{self._employeeId} belongs to {self._name}")
# Creating an instance of the Employee class
emp1 = Employee("Emp-001")
emp1.get_details()
# Result: Emp-001 belongs to John Doe
print("Inheritance:")
emp1.set_name("Bob Doe")
emp1.get_details()
# Result: Emp-001 belongs to Bob Doe
# Mini Exercise 2:
# Create a new class called Student that inherits Person with the additional attributes and methods.
# Attributes:
# Student No
# Course
# Year Level
# Methods:
# Necessary getters and setters
# get_detail: prints the output `<Student name> is currently in year <year level> taking up <course>`
# Solution:
class Student(Person):
def __init__(self, studentNo, course, year_level):
super().__init__()
self._studentNo = studentNo
self._course = course
self._year_level = year_level
# getters
def get_studentNo(self):
print(f"Student number of Student is {self._studentNo}")
def get_course(self):
print(f"Course of Student is {self._course}")
def get_year_level(self):
print(f"The Year Level of Student is {self._year_level}")
# setters
def set_studentNo(self, studentNo):
self._studentNo = studentNo
def set_course(self, course):
self._course = course
def set_year_level(self, year_level):
self._year_level = year_level
# custom method
def get_details(self):
print(f"{self._name} is currently in year {self._year_level} taking up {self._course}.")
# Creating an instance of the Student class
student1 = Student("stdt-001", "Computer Science", 1)
student1.set_name("Brandon Smith")
# Result: Brandon Smith
student1.get_details()
# Result: Brandon Smith is currently in year 1 taking up Computer Science.
# [SECTION] Polymorphism
# A child class inherits all the methods from its parent class. However, in some situations, a method inherited from the parent class may not fully suit the child class. In such cases, you need to re-implement the method in the child class.
# Polymorphism in Python refers to defining methods in the child class with the same name as those in the parent class.
# Through inheritance, the child class can reuse methods from the parent class, but it can also modify or override them to fit its own needs.
# Polymorphism with Inheritance
class Zuitt():
def tracks(self):
print('We are currently offering 3 tracks(developer career, pi-shape career, and short courses)')
def num_of_hours(self):
print('Learn web development in 360 hours!')
class DeveloperCareer(Zuitt):
# Override the parent's num_of_hours() method
def num_of_hours(self):
print('Learn the basics of web development in 240 hours!')
class PiShapedCareer(Zuitt):
# Override the parent's num_of_hours() method
def num_of_hours(self):
print('Learn skills for no-code app development in 140 hours!')
course1 = DeveloperCareer()
course2 = PiShapedCareer()
print("Polymorphism:")
course1.num_of_hours()
# Result: Learn the basics of web development in 240 hours!
course2.num_of_hours()
# Result: Learn skills for no-code app development in 140 hours!
# Mini Exercise 3:
# Add another child class named ShortCourses
# Method “num_of_hours” should print: Learn advanced topics in web development in 20 hours!
# Solution:
class ShortCourses(Zuitt):
def num_of_hours(self):
print("Learn advanced topics in web development in 20 hours!")
# Mini Exercise solution
course3 = ShortCourses()
# Mini Exercise solution
course3.num_of_hours()
# Result: Learn advanced topics in web development in 20 hours!
# Polymorphism with Functions and Objects
# You can use different functions, class methods, or objects to demonstrate polymorphism.
# A function can be created that accepts any object, allowing polymorphic behavior.
class Admin():
def is_admin(self):
print(True)
def user_type(self):
print('Admin User')
class Customer():
def is_admin(self):
print(False)
def user_type(self):
print('Regular User')
# Define a test function that takes an object called obj
def test_function(obj):
obj.is_admin()
obj.user_type()
# Create object instances for Admin and Customer
user_admin = Admin()
user_customer = Customer()
# Pass the created instances to the test_function
test_function(user_admin)
# Result:
# True
# Admin User
test_function(user_customer)
# Result:
# False
# Regular User
# The test_function calls the methods of the object passed to it, producing different outputs depending on the object type.
# Polymorphism with Class Methods
# Python can use different class types in the same way.
# For example, a for loop can iterate through a collection of objects.
# The loop calls the same methods on each object, regardless of its class type.
class TeamLead():
def occupation(self):
print('Team Lead')
def hasAuth(self):
print(True)
class TeamMember():
def occupation(self):
print('Team Member')
def hasAuth(self):
print(False)
tl1 = TeamLead()
tm1 = TeamMember()
for person in (tl1, tm1):
# Call the occupation method on each object
person.occupation()
person.hasAuth()
# Result:
# Team Lead
# True
# Team Member
# False
# In each iteration, the variable "person" refers to either tl1 or tm1, depending on the order in the loop. This demonstrates polymorphism in action.
# [SECTION] Abstraction
# An abstract class can be considered a blueprint for other classes. It allows you to define a set of methods that must be implemented in any child class that inherits from it.
# A class that contains one or more abstract methods is called an abstract class.
# An abstract method is a method that is declared but contains no implementation.
# Abstract classes are used to provide a common interface for different classes with different implementations.
# By default, Python does not support abstract classes directly. However, it provides the abc module, which allows you to define Abstract Base Classes (ABCs).
from abc import ABC, abstractmethod # Importing ABC and abstractmethod from the abc module
# Polygon inherits from ABC, making it an abstract class
class Polygon(ABC):
# Abstract method that must be implemented by any subclass
@abstractmethod
# This method is meant to be overridden in subclasses; no implementation here
def printNumberOfSides(self):
# The pass keyword indicates that the method is intentionally left blank
pass
class Triangle(Polygon):
def __init__(self):
super().__init__()
# Implementation of the abstract method
def printNumberOfSides(self):
print("This polygon has 3 sides.")
class Pentagon(Polygon):
def __init__(self):
super().__init__()
# Implementation of the abstract method
def printNumberOfSides(self):
print("This polygon has 5 sides.")
# Create instances and call the method
shape1 = Triangle()
shape2 = Pentagon()
print("Abstraction:")
shape1.printNumberOfSides()
# Result: This polygon has 3 sides.
shape2.printNumberOfSides()
# Result: This polygon has 5 sides.