CS 112
Intro to Programming
Basic OO Concepts
George Mason University
Building up to classes:
Python Data Types
2
Primitive Data Types:
integer, floating point, boolean, None, etc
Complex Data Types:
Sequence: String, Tuple, List
Mapping: Dictionary
Class: User-created
DEFINING
CLASSES
Making Our Own Types:
Classes
We can move beyond the existing types of our language.
we're not restricted to using just int, float, str, list, tuple,
set, dictionary, …
Each type can be thought of as a set of values:
bool = {True, False}
NoneType = {None}
int = {…,-2,-1,0,1,2,…}
person = … ??? …
address = … ??? …
Making Our Own Types:
Classes
We create our own new types with a
class definition: a 'blueprint' of what is present
for a value of this type:
what pieces of data (variables inside)
what behaviors (methods available)
Example Class
# define an entire new class of python values
class Person:
# method describing how to create any one new Person value
def __init__ ( self , name_param, age_param ):
# store param to 'long-term' instance variables
self . name = name_param
self . age = age_param
Let's define a Person as having a name and an age:
create a Person value (an object) by calling its constructor:
george = Person("George",66)
this actually calls the __init__ definition, by using
the class name Person. Note that the self parameter
seems to have been supplied some other way!)
Classes in Python
7
Class Definition (blueprint)
class definition tells Python everything about the new data type
Object Instantiation (creation)
An object must be instantiated (created) from the class definition
via the __init__ method, to fill in instance variables, before it
can be used.
Object manipulation (use)
Once object exists, we can read/update its data (access its
instance variables), and use its behaviors (call its methods)
Class Definition
A Python class definition contains:
name (identifier) of the class
optional: name of parent class. (often, just object)
constructor (method named __init__)
defines, instantiates the instance variables
methods (behavior)
Example: The Point class
A Point is an (x,y) coordinate pair.
data: the actual x, y values.
methods: shift, vector_magnitude, etc.
We define a Point class once, so that we can
make lots of Point objects.
our Point methods only work on Points
(this is good)
Point class
class Point:
#constructor: how to make a Point.
def __init__ (self, xparam, yparam):
# creates an x, and a y, for the object.
self.x = xparam
self.y = yparam
__init__ method: tells us how to create a Point object.
all methods, not just constructor methods, have self as
a first parameter. We must use self to access the
object's data and methods from within the class's code
Constructor Methods
11
constructor method is named __init__
note: double underscores on both sides (_ _ i n i t _ _ )
primary duty: assign values to the object's attributes
must have at least one first formal parameter (name it self)
may have as many more params as needed/desired.
Calling a constructor (via the class name) tells Python to:
instantiate (create) a new object of the class data type
example: Point(1,2)
set the object’s initial state (run constructor's code)
example: self.x becomes 1, self.y becomes 2.
return a reference to the new object to the caller
Defining Attributes
self.x is assigned to create the instance variable
named x.
re-assigns if we see another self.x assignment
all instance variables ought to be added in the
constructor.
every single Point object we make has its own x, and its own y.
class Point:
#constructor: how to make a Point.
def __init__ (self, xparam, yparam):
# creates an x, and a y, for the object.
self.x = xparam
self.y = yparam
Instance Variables
13
We can make many objects from a single class definition.
Each object is an instance of the class, so each variable
that exists inside the object is called an instance variable.
Class example instance variables
Person
name, age, height
Address
state,
zip, city, county, street, num
Popsicle
color, flavor, size,
is_frozen
Episode
show_name
, genre, season, ep_num, runtime
<Anything>
<you choose what state is important for your program!>
POLL 9A
class definitions
Practice Problem
For each of the following, define a class, with its constructor, that
represents it.
A Student has a name, a student ID, and a GPA.
A stop-light has a status which is "red", "green", or "amber".
Come up with a good example class. When would it be helpful?
CREATING
OBJECTS
Object Components
objects contain two different things:
attributes
characteristics of the object (instance variables)
behaviors
actions of the object (methods)
17
Using These Types: Making Objects
A class defines a new type.
objects are the actual values of this type
An object instantiates the class definition by
calling the __init__ method, supplying values
for each parameter except for the first one
(which is traditionally named self).
Example Objects
>>> george_mason = Person("George",66)
>>> william = Person("Bill Shakespeare",52)
>>>
>>> george_mason . age
66
>>> william . age
52
>>> george_mason . name
'George'
>>> william . age = 2019 - 1616 + (william.age)
>>> william . age
455
Understanding Objects as Values
5 is an instance of an int. So is 6.
They behave differently when we use them.
xs=[1,2,3] and ys=[4,5] both refer to lists
but contain different data.
The same methods are available on each list (such as
append, extend, sort, etc), but they respond differently
If we modify one, the other is not affected.
we're only discussing values here (not aliases)
two Person objects are both instances of the Person class.
They may have different names, ages, etc.
have same methods (b/c each is a Person).
Each object is an instance of its class type.
Point Objects
Create an object – an instance of the class –
by calling the constructor.
p1 = Point(1,2) #call constructor
p2 = Point(3,4) #call constructor
print ("point 1: ", p1.x, p1.y)
print ("point 2: ", p2.x, p2.y)
print(p1)
point 1: 1 2
point 2: 3 4
<__main__.Point object at 0x1005c9ad0>
Access attributes with the dot-operator:
Syntax: objectExpr . attribute Example: p1 . x
POLL 9B
objects
Practice Problem
In an interactive session, load your classes from before, and:
Create two objects each of your Student and Stoplight classes.
print some of their instance variables out
modify the values of some instance variables
print them again
print the whole objects out – how do they look? good, bad?
DEFINING
METHODS
Defining Methods
A method in our class implements functionality
that is only appropriate upon an object of the
class. They look a lot like function definitions
indented inside of a class.
Always have self as first parameter.
Each object can use this method on its personal
data (through self). The method may:
access or update instance values
return values based on instance values
Adding a Method
the method accesses instance variables through self.
values modified directly – the "side effect" of calling the method
is that x and y change values.
no return statement present in our particular shift method,
but just like functions, we always return something; return
statements are normal in methods just as in functions.
in this case, None is implicitly returned
class Point(object):
#constructor, etc.
def shift (self, xshift=0, yshift=0):
self.x += xshift
self.y += yshift
Better Printing:
provide __str__ definition
class Point:
# __init__ constructor, etc. not shown
def __str__ (self):
s = "Point("+str(self.x)+","+str(self.y)+")"
return s
>>> p1 = Point(1,2)
>>> print(p1)
Point(1,2)
We are overloading the str() functionality.
str() looks for the __str__ method and calls it.
this is an example of polymorphism: str() works on
many types, with __str__ definitions added in ad-hoc fashion.
Practice Problem
add a go_to_origin method that changes a Point back
to the origin.
where does it go?
what is its return type?
how many arguments does it have?
add a quadrant method, that returns a number from
1 to 4 based on which quadrant the Point is in.
Return 0 if the point is on either axis.
1:(+,+). 2:(-,+). 3:(-,-). 4:(+,-).
answer the three 's from the previous question.
Practice Problem
Create an object of the Point class, and place it
not at the origin. Call the shift and origin methods
so that you can print subsequent calls to the
quadrant method, and get a different answer each
time.
Q: If you create three Point objects, how many
integers were stored in memory?
if you call origin() on one of the three Points,
does this affect the other two Point objects?
Practice Problem
add a vector_magnitude method that calculates the
distance from the origin, returning the float value.
add a slope method that accepts another Point
argument, and calculates the slope from the self-point
to the argument-point, returning that value.
Using a method
p1 = Point(1,2)
p2 = Point(3,4)
print(p1)
p1.shift(5,5)
print(p1)
p1.shift(yshift=3)
print(p1)
print("\np2:",p2)
print("p2:",p2.__str__())
print("p2:",str(p2))
Point(1,2)
Point(6,7)
Point(6,10)
p2: Point(3,4)
p2: Point(3,4)
p2: Point(3,4)
Both Point objects have their own state. p1 gets modified repeatedly, but
p2 stays the same. They are separate values.
Note: the self parameter's argument is p1 itself, so it doesn't show up in
the ()'s. It shows up in front of the method name. All methods are called
this way.
Various Ways to Display
p2 = Point(3,4)
print("p2:",p2.__str__())
print("p2:",str(p2))
print("p2:",p2)
p2: Point(3,4)
p2: Point(3,4)
p2: Point(3,4)
we can manually call _str__ on our Point object if we want.
str() looks for a definition of __str__ to call
print() calls str()
all three have the same effect.
Practice Problem
What is printed?
p1 = Point(1,1)
p2 = p1
p2.x = 2
print("first: ",p1)
p3 = Point(3,3)
p1 = Point(5,5)
print("1: ",p1)
print("2: ",p2)
print("3: ",p3)
first: Point(2,1)
1: Point(5,5)
2: Point(2,1)
3: Point(3,3)
p2 is an alias for p1, and then
p1 is reassigned to a different
object memory. Use the
visualizer to see the memory.
Functions vs. Methods
34
Functions define a conversion from arguments to return-
value.
sqrt(25) accepts argument, calculates/returns 5.0
Methods act upon objects of some particular type only, yet
also accept arguments and calculate return value.
Assumed that it might modify the object's state.
You could always define a method as a function instead,
but it's tidy to put methods where they belong – avoid
calling it on incorrect types of data.
POLL 9C
methods
SCOPE, VISIBILITY
Scope and Methods
class Point (object):
def __init__ (self, x,
y):
self.x = x
self.y = y
Method parameters only exist during a particular call of
the method.
Instance variables' values live as long as the object lives
(is accessible from any part of your code)
Convention: name parameter and attribute the same. x
and self.x are different. y and self.y also.
A Need for Privacy
Sometimes data is 'sensitive' – either shouldn't be
known outside an object, or at least shouldn't be
directly modifiable by outsiders.
a BankAccount object's balance shouldn't just be
readily modifiable, it should only be accessed in
controlled fashion: through methods.
Unsecure Account
class Account:
def __init__ (self, start_bal=0):
self.bal = start_bal
def withdraw(self, amount):
self.bal -= amount
return amount
def deposit(self, amount):
self.bal += amount
Unsecure Attribute Usage
a = Account(50)
print(a.bal)
a.withdraw(-100)
print(a.bal)
a.bal = 9999999999
print(a.bal)
50
150
9999999999
!
!
!
! withdraw method is too trusting.
! the bal attribute shouldn't be directly accessible,
neither for reading or writing.
Approach to Privacy:
Private Attributes/Methods
attributes whose identifiers begin with a double-
underscore are private: the dot-operator access
doesn't work from outside the object.
unfortunately, Python does allow the programmer to
access the private attribute, or private method, via the
underscore-classname-attribute name. Example: a
SafeAccount object's __bal can be accessed outside of
the object with
accountExpr . _SafeAccount__bal
Better (Private) Attribute Usage
class SafeAccount:
def __init__ (self, start_bal=0):
self.__bal = start_bal
def withdraw(self, amount):
if amount>0 and self.__bal>=amount:
self.__bal -= amount
return amount
return 0
def deposit(self, amount):
self.__bal += max(0,amount)
def current_balance(self):
return self.__bal
Secure Attribute Usage
a = SafeAccount(50)
print(a.current_balance())
a.withdraw(-100)
print(a.current_balance())
a.deposit(-100)
print(a.current_balance())
#errors (unallowed):
# a.bal = 9999999999
# a.__bal = 9999999999
#allowed, circumvents privacy:
print(a._SafeAccount__bal)
50
50
50
50
Python still creates
underscore-classname-
attribute as an attribute, so
it's not truly private.
This is Python's "we're all
adults" approach. Makes it
harder, but not impossible,
to access it.
Practice Problems
Thoughts: did making bal private…
make withdraw or deposit safer?
preclude *any* abuses of bank accounts?
add a pin number to the bank account.
should it be private?
how might we use it? (not a simple answer)
Recipe:
Using OO in Python
Choose your data representations when starting up
a new project. Some of these choices may mean you
create new classes.
Add attributes and behaviors to the class definitions,
so that they are useful for your particular project.
Create objects of this class while implementing your
project, instead of just using lists, tuples, etc.
???
PROFIT
BASICS OF
OBJECT-ORIENTED
PROGRAMMING
Object Oriented Programming
In this style, the programmer tries to model the
system by defining what objects exist, and how
they behave
A program is then essentially making the right
objects, and then watching them interact or
create other objects.
Object Oriented Programming
create classes for relevant structures of a project.
define objects' state/behavior as variables and
methods.
create objects for everything that interacts, let
them interact to model the world.
Encapsulation
Encapsulation means using barriers or boundaries to
keep related things together, and unrelated things
apart from each other.
Attributes and behaviors are enclosed (encapsulated)
within the logical boundary of the object entity
In structured or procedural systems, data and code
are typically maintained as separate entities (e.g.,
functions here, and specific lists of data over there)
In OO systems, each object contains the data
(attributes) and the code (behaviors) that operates
upon those attributes
49
Abstraction
Encapsulation implements the concept of abstraction:
details associated with object sub-components are
enclosed and hidden within the logical boundary of
the object
user of object only “sees” the abstract perspective
offered by the object
Note - In Python, encapsulation is merely a programming convention –
other languages (e.g., Java) enforce the concept more rigorously.
50
Encapsulation
Putting related values and related code (methods)
together gives us encapsulation. Good organization
always helps!
Centralizing definitions means we have one place to
make modifications.
INHERITANCE
Inheritance
We can create class definitions out of other
classes, adding more variables and more
methods.
Promotes code reuse by allowing more specific
sub-classes to be derived from more generic
super-classes
defines child class and parent class relations.
53
Inheritance
child inherits attributes/behaviors of parent
may add additional attributes/behaviors
thus making the child more specific
The child-class type is a subtype of the parent-
class type.
Every object of child class is still a value of the
parent class type.
a Student is a Person. A Cat is an Animal.
(similar idea:) every int can be represented as
a float, but not vice versa.
54
Inheritance - example
55
Vehicle
Car
generic attributes/behaviors here:
VIN, color, year, etc.; accelerate,
brake, etc.
Truck
SUVPickup
more specialized
attributes/behaviors: 4-wheel
drive, towing hitch, etc.;
engage 4-wheel drive,
open_trunk, etc.
very specialized details: bed
canopy; rear seat DVD player;
operate_winch; etc.
Aggregation
Behaviors
Name
Person
Aggregate Objects
Objects may declare and
instantiate other objects as
attributes
56
Behaviors
"George"
Behaviors
Aggregation is the collecting of other (possibly complex)
values. An object can have other objects as data, just like a list
can have other lists as items inside of it.
addr
Address
city
zip
String
Aggregation - example
57
Desktop
Computer
Base
Unit
Monitor
A Desktop Computer can contain
aggregate units as attributes
Disk
Drive
Mother
Board
Each aggregate unit
can in turn contain
other aggregate units
Do not confuse:
inheritance relationships
with
aggregate relationships
Inheritance vs Aggregation
"IS-A": Inheritance embodies the "is-a"
relationship: A Student "is a" Person; a Truck
"is a" Vehicle.
"HAS-A": Aggregation embodies the "has-a"
relationship: A Student "has a" GPA. A Car
"has a" Wheel.
Exceptions Revisited
Exception classes heavily utilize an inheritance
hierarchy.
We can create our own exception classes, add our
own useful variables, methods, etc.
We can extend existing classes to piggyback on the
appropriate exception handling code.
go visit our Exceptions slides for more
info on making Exception classes.