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
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. |