0% found this document useful (0 votes)
4 views

Object Oriented Programming Introduction in Python

OOP in Python basics with analogies

Uploaded by

Sri Dhanya
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

Object Oriented Programming Introduction in Python

OOP in Python basics with analogies

Uploaded by

Sri Dhanya
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 80

Formatting Output

• Some student ask what is this “f” in the print statement


>>> x = 1
>>> print('The value of x is {x}.')
The value of x is {x}.
>>> print(f'The value of x is {x}.')
The value of x is 1.
• When we use “f”, whatever inside {} will be evaluated
• You can get around WITHOUT that
>>> print('The value of x is '+str(x)+'.')
The value of x is 1.
Object-Oriented
Programming
OOP
Recap: Tables
• Just like other Spreadsheet applications
Name Stu. No. English Math Science Social Studies
John A1000000A 90 80 100 70
Peter A1000009D 60 100 60 90
Paul A1000003C 80 80 70 90
Mary A1000001B 100 70 80 80

• How about more “attributes”


Name Stu. No. Gender Year English Math Science Social Studies
John A1000000A M 2018 90 80 100 70
Peter A1000009D M 2018 60 100 60 90
Paul A1000003C M 2017 80 80 70 90
Mary A1000001B F 2019 100 70 80 80
NUS Application
Stored as a 2D Array
• Like in Spreadsheet applications
Name Stu. No. English Math Science Social Studies
John A1000000A 90 80 100 70
Peter A1000009D 60 100 60 90
Paul A1000003C 80 80 70 90
Mary A1000001B 100 70 80 80

• Or, you can setup a more “comprehensible” column index dictionary


Isn’t it nicer?
>>> alan.name
'Alan'
>>> alan.gender
'M'
>>> alan.sci
80
>>> alan.math
100
>>> mary.name
'Mary'
>>> mary.sn
'A1000002A'
>>> allStudents = [alan,mary]
>>> allStudents[0].name
'Alan'
>>> allStudents[1].sn
'A1000002A'
Class and Instance
Definitions
• Class:
• specifies the common behavior of entities.
• a blueprint that defines properties and behavior of an object.
• Instance:
• A particular object or entity of a given class.
• A concrete, usable object created from the blueprint.
Classes vs Instances
• Class • Instance
• Blueprints, designs • Actual copies you use

One blueprint can produce a lot of copies of iPhone


One class can produce a lot of copies of instances
Example
• String is a class in Python

• The variable s above, is an instance of the class str (String)


• And you can create other instances, e.g. s1, str1, s2, etc. of ONE class str
• And each instance will store different values
Designing our own class
• Python OOP means we can design our own class and methods!

• Let’s try to create a class called “StudentRecord”


Class StudentRecord
• Design
• In a student record, we want to
store
• Name, student number, gender,
year, and marks for English,
math, science and social studies
• Or maybe more?

In OOP, these are


called attributes
Class StudentRecord
• Design
• In a student record, we want to
store
• Name, student number, gender,
year, and marks for English,
math, science and social studies
• Or maybe more? ↕
• But this is ONLY the class
• Namely the blueprint
• Can we use this phone
blueprint to call someone?
• You have to MAKE a phone by it
Create an Instance
• When you create a new instance/variable:
>>> alan = StudentRecord()
• It’s like you create a new variable x for integer
>>> x = 1
• A new instance/variable is born/created
• Important:

When you create an instance, the


constructor function is called
A “self” variable?
• Every class definition has access to a self variable
• self is a reference to the entire instance
What is __init__()?
• def __init__(self):
• called when the object is first initialized
• self argument is a reference to the object calling the method.
• It allows the method to reference properties and other methods of
the class.
• Are there other special methods?
• Yes! Special methods have __ in front and behind the name
Create an Instance
• When you create a new instance/variable:
>>> alan = StudentRecord()
• When you create an instance, the constructor
function is called
• What? What constructor?!
• In every class, you have to define a function
called “__init()__”
With two underscores “_ _”
• “self” means your own record
• To distinguish from a local variable in a function (as we had
learn so far) that will be destroyed after the function ended
Create an Instance
• When you create a new instance/variable:
>>> alan = StudentRecord()
• When you create an instance, the constructor
function is called
• So after the line above, the instance alan will
contain
• So, the values in the constructor can be considered
the default vales for initialization
You Store Values into an Instance

Before the red arrow Finally. (Oops, I


forgot to assign
“year”)
Create as Many Instances
as You Want
A “self” variable?
• Every class definition has access to a self variable
• self is a reference to the entire instance
• A self variable will NOT disappear when the function exits
With or without “self.”
• The variable “name” will disappear after the
completion of the function __init__()
• The variable “self.name” will remain after
the completion of the function
__init__()
Other than Student Records
Or Bank Accounts
• What attributes should we store in a bank
account record?
• Name
• Balance
• Isn’t it a bit clumsy to set the values?
• We know that some attributes must be
initialized before used
Initialization through Constructors
• We know that some attributes must be initialized before used
• When we create an instance, we initialize through the constructor

• It is a good way to “force” the instance to be initialized


Modifying Attributes
• Of course, we can change the attributes of any instance

• However, is it always good to be changed like that?

• There are always some rules to control how to modify the attributes
• In real life, how do you withdraw money from your account?
“Rules”
• Can you walk in the bank and get any amount even more than your
balance? Or any other bank transactions?
• Must through some “mechanism”, e.g.
• Bank tellers, ATM, phone/internet banking, etc.
• And these mechanisms have some rules,
• E.g. you cannot withdraw more than your balance
Bank Accounts with “Methods”

Attributes

Methods
Bank Accounts with “Methods”
>>> myAcc = BankAccount('Alan',1000)
>>> myAcc.showBalance()
Your balance is $1000
>>> myAcc.withdraw(123)
123
>>> myAcc.showBalance()
Your balance is $877
>>> myAcc.withdraw(99999)
Money not enough! You do not have $99999
0
Is it a *really* a new thing?
• Recall your previous lectures…
lst = [1, 2, 3]
lst.append(4)
lst [1, 2, 3, 4]

• Conceptually, append is a method defined in the List class.


• Just like withdraw is a method defined in the BankAccount
class
Inheritance
Let’s Define a class Sportcar
Test Run
>>> myCar = Sportscar((0,0))
>>> myCar.setVelocity(0,40)
>>> myCar.move()
Move to (0, 40)
>>> myCar.turnOnTurbo()
VROOOOOOOM......
Velocity increased to (0, 80)
>>> myCar.move()
Move to (0, 120)
How about a class Lorry?
How about a class Lorry?
Test Run
>>> myTruck = Lorry((10,10)) >>>myTruck.unload("Food")
>>> myTruck.setVelocity(10,0) Cargo Food unloaded.
>>> myTruck.move() >>> myTruck.inventory()
Move to (20, 10) Inventory:['Supplies']
>>> myTruck.load("Food") >>> myTruck.unload("Gold")
>>> myTruck.load("Supplies") Cargo Gold not found.
>>> myTruck.inventory()
Inventory:['Food', 'Supplies']
Compare the Two Classes
Sportscar Lorry
• Attributes • Attributes
• pos • pos
• velocity • velocity
• cargo
• Methods • Methods
• __init__() • __init__()
• setVelocity() • setVelocity()
• move() • move()
• turnOnTurbo() • load()
• unload()
• inventory()

What are the common attributes/methods?


Compare the Two Classes
Sportscar Lorry
• Attributes • Attributes
• pos • pos
• velocity • velocity
• cargo
• Methods • Methods
• __init__() • __init__()
• setVelocity() • setVelocity()
• move() • move()
• turnOnTurbo() • load()
• unload()
• inventory()

What are the common attributes/methods?


Extract the Vehicle
• Attributes
Common • pos
Pattern! • velocity
• Methods
• __init__()
• setVelocity()
• move()

Sportscar Lorry
• Methods • Attributes
• __init__() • cargo
• turnOnTurbo() • Methods
• __init__()
• load()
• unload()
• inventory()
The Classes Vehicle and Sportcar

Sportscar inherits EVERYTHING from Vehicle


How about Lorry?
• In the OLD Lorry code

Extra to the __init__()


in Vehicle
If We Inherit Lorry from Vehicle
• Two ways to implement the
constructor
• Method 1: Overriding
• Simple redefining the method will
override the one in Vehicle
or
• Method 2: Calling super class
• Redefine a constructor, but call the
constructor in super() (Vehicle
class) instead
Super()
• A way to access a method in your parent/higher classes
Which one is better?
• Usually we prefer Method 2
because
• No duplication of code

• Method 2: Calling super class


• Redefine a constructor, but call the
constructor in super() (Vehicle
class) instead
Class Lorry
• Inherit all what class
Vehicle has
• In addition, add
more functionalities
like load() and
unload()
Vehicle
• Attributes
Overall Picture • pos
Super class
or
Parent class
• velocity
• Methods
• __init__()
• setVelocity()
Subclass • move()
or
Child class

Sportscar Lorry
• Methods • Attributes
• __init__() • cargo
• turnOnTurbo() • Methods
• __init__()
• load()
• unload()
• inventory()
Inheritance
• Objects that exhibit similar functionality should “inherit” from the
same base object, called the superclass.
• An object that inherits from another is called the subclass.
Subclass and
Superclass
• Usually a subclass is a more
specific type of its parent
class
• Like our classification of
animals, any “children” in
the tree is a more “specific”
type of the “parents”
• (Unless we talk about
multiple inheritance later)
Let’s define a new class Bisarca
• Car carrier trailer
• It is a type of truck that carries other cars
• The truck and also load and unload, but only for cars
• not any type of cargos
Where should
we put class Vehicle
Bisarca? • Attributes: pos,velocity
• Methods:__init__(),setVelocity(),move()

Sportscar Lorry
• Methods: __init__(), • Attributes: cargo
turnOnTurbo() • Methods:__init__(),load(),unload()
,inventory()

Bisarca
• Methods: load()
Class Bisarca

• The function isinstance(obj,cal) check if an instance obj is


a class or subclass of a certain class cal.
Sample Run
>>> myDadTruck = Bisarca((0,0))
>>> myDadTruck.load("Food")
Your cargo (Food) is not a vehicle!
>>> myDadTruck.load(myCar)
>>> myDadTruck.load(myTruck)
>>> myDadTruck.inventory()
Inventory:[<__main__.Sportcar object at 0x10d3ecd50>,
<__main__.Lorry object at 0x10d39dc10>]
Method Overriding
• When you redefine a same method that was in your parent class
• You own class will call your new redefined method
• Instead of your parent’s one
• This is called overriding Lorry
• Attributes: cargo
• Methods:__init__(),load(),unload
(),inventory()

Bisarca
• Methods: load()
Multiple Inheritance
Let’s Create a Class Cannon
Class Cannon
• Sample run:
>>> myCannon = Cannon()
>>> myCannon.fire()
No more ammo
>>> myCannon.reload()
Cannon reloaded
>>> myCannon.reload()
Unable to reload
>>> myCannon.fire()
Fire!!!!!!!
>>> myCannon.fire()
No more ammo
What Do You Have When You…
• Merge a cannon and a vehicle?

+ =
We Want to Have BOTH!
>>> myTank = Tank((0,0))
>>> myTank.setVelocity(40,10)
>>> myTank.move()
Move to (40, 10)
>>> myTank.move()
Move to (80, 20)
>>> myTank.reload()
Cannon reloaded
>>> myTank.fire()
Fire!!!!!!!
Where should we put the class Tank?
Vehicle Cannon
• Attributes: pos,velocity • Attributes: numAmmo
• Methods: setVelocity(),move() • Methods: fire()

Sportscar Lorry Tank


• Methods: __init__(), • Attributes: cargo
turnOnTurbo() • Methods:__init__(),load(),
unload(),inventory()

Bisarca
• Methods: load()
A Bit Trouble
• Which constructor __init__() should the Tank call?

• Seems like we need BOTH

Call BOTH!!!
Resolving Methods
So far we have
Vehicle Cannon
• Attributes: pos,velocity • Attributes: numAmmo
• Methods: setVelocity(),move() • Methods: fire()

Sportscar Lorry Tank


• Methods: __init__(), • Attributes: cargo
turnOnTurbo() • Methods:__init__(),load(),
unload(),inventory()

Bisarca
• Methods: load()
What Do You Have When You…
• Merge a Bisarca and a Lorry?

+ =
Let’s Construct Class BattleBisarca

• Wait… Which load() is called?


Vehicle Cannon
• Attributes: pos,velocity • Attributes: numAmmo
• Methods: setVelocity(),move() • Methods: fire()

Lorry
• Attributes: cargo Which
• Methods:__init__(),load() load() is
,unload(),inventory()
called by
Bisarca BattleBisarca
• Methods: load() ?
BattleBisarca
Vehicle Cannon
• Attributes: pos,velocity • Attributes: numAmmo
• Methods: setVelocity(),move() • Methods: fire()

Lorry
• Attributes: cargo The nearest
• Methods:__init__(),load() one will be
,unload(),inventory()
called
Bisarca
• Methods: load()

BattleBisarca
Let’s Constuct Class BattleBisarca

• Wait… Which load() is called?


>>> OptimasPrime = BattleBisarca((0,0))
>>> OptimasPrime.load("Food")
Your cargo (Food) is not a vehicle!
Class A
Multiple Inheritance
• Complication arises when the same
method is available in two distinct Class B Class C
superclasses
• And how about Diamond Inheritance
• But if you are really interested in these Class D
• Check out:
• http://python-
history.blogspot.com/2010/06/method-
resolution-order.html
Multiple Inheritance
• Not many OOP Language support MI
• E.g. no MI in C++, Java
• MI causes more trouble sometime because you may call the
unexpected method in a complicated inheritance structure
• Recommendation is, only use MI if the parents are very different
• E.g. Vehicle and Cannon
• Or Tablet (computer) + calling device = smart phone
Private vs Public
Private vs Public
• So far, all our methods in a class are all public
• Meaning they can be called with the instance
• E.g. for the class BankAccount
• Even we set up the method withdraw() to “prevent” illegal access

• But we can still do


>>> myAcc.showBalance()
Your balance is $1000
>>> myAcc.balance -= 9999
>>> myAcc.showBalance()
Your balance is -$8999
Another Example: Remember the Bisarca?
>>> myDadTruck.load(myCar) So ugly
>>> myDadTruck.load(myTruck)
>>> myDadTruck.inventory()
Inventory:[<__main__.Sportcar object at
0x10d3ecd50>, <__main__.Lorry object at
0x10d39dc10>]
• What I really want is
>>> myDadTruck.inventory()
Inventory:['Sportscar', 'Lorry']
So I change my Bisarca class into

• Wait, but I actually do not want anyone to use the method


convertCargo(), it’s not for anyone
• I want to make it private
Private Methods
• If you add two underscore before the method name
class Bisarca(Lorry):
def __convertCargo(self):
output = []
for c in self.cargo:
output.append(str(type(c)).split('.')[1].split('\'')[0])
return output
def inventory(self):
print("Inventory:"+str(self.__convertCargo()))
• That function can be used inside your class but cannot be called outside!
>>> myDadTruck.__convertCargo()
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
myDadTruck.__convertCargo()
AttributeError: 'Bisarca' object has no attribute '__convertCargo'
Private but not Private
• However, it’s not very true…
• You can add ‘_’ and the class name to access it
>>> myDadTruck._Bisarca__convertCargo()
['Sportscar', 'Lorry']
• But why do we have this?!
“Private” Methods
• Originally, in a lot of other OOP languages (e.g. C++, Java), a private
method/variable will NOT be accessible by anyone other than the
class itself.
• The purpose is to prevent any programmers to access the
method/variable in a wrong way
• E.g. directly change the balance of a bank account like
myAcc.balance = 100000000
• However, Python does not have that “full protection”
Conclusion
Benefits of OOP
• Pros
• Simplification of complex, possibly hierarchical structures
• Easy reuse of code
• Easy code modifiability
• Intuitive methods
• Hiding of details through message passing and polymorphism
• Cons
• Overhead associated with the creation of classes, methods and instances
Major Programming Paradigms
• Imperative Programming
• C, Pascal, Algol, Basic, Fortran
• Functional Programming
• Scheme, ML, Haskell,
• Logic Programming
• Prolog, CLP
• Object-oriented programming
• Java, C++, Smalltalk

Python??

You might also like