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

Module 5

The document discusses object-oriented programming concepts like classes, objects, methods, and class definitions. It explains how classes are used to define new types that combine both code and data, and how methods are defined within classes to represent the behaviors of objects.

Uploaded by

impanac147
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
84 views

Module 5

The document discusses object-oriented programming concepts like classes, objects, methods, and class definitions. It explains how classes are used to define new types that combine both code and data, and how methods are defined within classes to represent the behaviors of objects.

Uploaded by

impanac147
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 77

At this point you know how to

use functions to organize code


built-in types to organize data.

The next step is to learn “object-oriented


programming”, which uses programmer defined
types to organize both code and data.
Module 5
 Classes and objects
 Classes and functions
 Classes and methods
Programmer-defined types
 To create a type called Point that represents a
point in two-dimensional space.

 For example, (0, 0) represents the origin, and


(x, y) represents the point x units to the right
and y units up from the origin.
There are several ways we might represent
points in Python:

 We could store the coordinates separately in

two variables, x and y.

 We could store the coordinates as elements in a

list or tuple.

 We could create a new type to represent points

as objects.
A programmer-defined type is also called a
class.
A class definition looks like this:

class Point:

"""Represents a point in 2-D space."""


The header indicates that the new class is called
Point.
The body is a docstring that explains what the
class is for.
You can define variables and methods inside a
class.
Python docstrings are the string literals that
appear right after the definition of a function
>>> Point
<class__main__.Point>
 Because Point is defined at the top level, its
“full name” is __main__.Point.

 The class object is like a factory for creating


objects. To create a Point, you call Point as if
it were a function

>>> blank = Point()


>>> blank
<__main__.Point object at 0xb7e9d3ac>
 Creating a new object is called

instantiation, and the object is an

instance of the class.

 Every object is an instance of some

class, so “object” and “instance” are

interchangeable.
Attributes
 We can assign values to an instance using dot
notation:
>>> blank.x = 3.0
>>> blank.y = 4.0
 A state diagram that shows an object and its

attributes is called an object diagram.


>>> x = blank.x
>>> x
3.0
>>>'(%g, %g% (blank.x, blank.y))
'(3.0, 4.0)’
>>> distance = math.sqrt(blank.x**2 +
blank.y**2)
>>> distance
5.0

def print_point(p):

print('(%g, %g ,% (p.x, p.y))


Rectangles
we could specify one corner of the rectangle
(or the center), the width, and the height.
• we could specify two opposing corners.
class Rectangle:
"""Represents a rectangle.
attributes: width, height, corner.""“

box = Rectangle()
box.width = 100.0
box.height = 200.0
box.corner = Point()
box.corner.x = 0.0
box.corner.y = 0.0
Instances as return values
def find_center(rect):
p = Point()
p.x = rect.corner.x + rect.width/2
p.y = rect.corner.y + rect.height/2
return p
>>> center = find_center(box)
>>> print_point(center)
(50, 100)
Objects are mutable
box.width = box.width + 50
box.height = box.height + 100
def grow_rectangle(rect, dwidth, dheight):
rect.width += dwidth
rect.height += dheight
>>> box.width, box.height
(150.0, 300.0)
>>> grow_rectangle(box, 50, 100)
>>> box.width, box.height
(200.0, 400.0)
Copying
 Aliasing can make a program difficult to read
because changes in one place might have
unexpected effects in another place. It is hard to
keep track of all the variables that might refer to
a given object.

 Copying an object is often an alternative to


aliasing. The copy module contains a function
called copy that can duplicate any object.
>>> p1 = Point()
>>> p1.x = 3.0
>>> p1.y = 4.0
>>> import copy
>>> p2 = copy.copy(p1)
>>> print_point(p1)
(3, 4)
>>> print_point(p2)
(3, 4)
>>> p1 is p2
False
>>> p1 == p2
False
If you use copy.copy to duplicate a Rectangle,
you will find that it copies the Rectangle
object but not the embedded Point.
>>> box2 = copy.copy(box)
>>> box2 is box
False
>>> box2.corner is box.corner
True
>>> box3 = copy.deepcopy(box)
>>> box3 is box
False
>>> box3.corner is box.corner
False
box3 and box are completely separate objects.
Debugging
>>> p = Point()
>>> p.x = 3
>>> p.y = 4
>>> p.z
AttributeError: Point instance has no attribute
'z'
>>> type(p)
<class '__main__.Point‘>

>>> isinstance(p, Point)


True

>>> hasattr(p, 'x')


True
>>> hasattr(p, 'z')
False
try:
x = p.x
except AttributeError:
x=0
 class: A programmer-defined type. A class
definition creates a new class object.
 class object: An object that contains
information about a programmer-defined type.
The
 class object can be used to create instances of
the type.
 instance: An object that belongs to a class.
 instantiate: To create a new object.
 attribute: One of the named values associated
with an object.
 embedded object: An object that is stored as
an attribute of another object.
 shallow copy: To copy the contents of an

object, including any references to embedded


 objects; implemented by the copy function in

the copy module.


 deep copy: To copy the contents of an object

as well as any embedded objects, and any


 objects embedded in them, and so on;

implemented by the deepcopy function in the


 copy module.
 object diagram: A diagram that shows

objects, their attributes, and the values of the


attributes.
Classes and functions
 Time

class Time:
"""Represents the time of day.
attributes: hour, minute, second""“
 time = Time()
 time.hour = 11
 time.minute = 59
 time.second = 30
Object diagram
Pure functions
 The function creates a new Time object, initializes its
attributes, and returns a reference to the new object.
This is called a pure function because it does not
modify any of the objects passed to it as arguments
and it has no effect, like displaying a value or getting
user input, other than returning a value.

def add_time(t1, t2):


sum = Time()
sum.hour = t1.hour + t2.hour
sum.minute = t1.minute + t2.minute
sum.second = t1.second + t2.second
return sum
add_time figures out when the movie will be done.
>>> start = Time()
>>> start.hour = 9
>>> start.minute = 45
>>> start.second = 0
>>>

>>> duration = Time()


>>> duration.hour = 1
>>> duration.minute = 35
>>> duration.second = 0

>>> done = add_time(start, duration)


>>> print_time(done)
10:80:00
Here’s an improved version:
def add_time(t1, t2):
sum = Time()
sum.hour = t1.hour + t2.hour
sum.minute = t1.minute + t2.minute
sum.second = t1.second + t2.second
if sum.second >= 60:
sum.second -= 60
sum.minute += 1
if sum.minute >= 60:
sum.minute -= 60
sum.hour += 1
return sum
Modifiers
 Sometimes it is useful for a function to modify the
objects it gets as parameters. In that case, the
changes are visible to the caller. Functions that
work this way are called modifiers.

def increment(time, seconds):


time.second += seconds
if time.second >= 60:
time.second -= 60
time.minute += 1
if time.minute >= 60:
time.minute -= 60
time.hour += 1
Prototyping versus planning
 Prototype that performed the basic calculation
and then tested it, patching errors along the
way. This approach can be effective, especially
if you don’t yet have a deep understanding of
the problem.

 An alternative is designed development, in


which high-level insight into the problem can
make the programming much easier
def time_to_int(time):
minutes = time.hour * 60 + time.minute
seconds = minutes * 60 + time.second
return seconds

def int_to_time(seconds):
time = Time()
minutes, time.second = divmod(seconds, 60)
time.hour, time.minute = divmod(minutes, 60)
return time
 Once you are convinced they are correct, you
can use them to rewrite add_time:

def add_time(t1, t2):


seconds = time_to_int(t1) + time_to_int(t2)
return int_to_time(seconds)
Debugging
def valid_time(time):
if time.hour < 0 or time.minute < 0 or
time.second < 0:
return False
if time.minute >= 60 or time.second >= 60:
return False
return True
def add_time(t1, t2):
assert valid_time(t1) and valid_time(t2)
seconds = time_to_int(t1) + time_to_int(t2)
return int_to_time(seconds)

assert statements are useful because they


distinguish code that deals with normal
conditions from code that checks for errors.
Glossary
 prototype and patch: A development plan that
involves writing a rough draft of a program,
testing, and correcting errors as they are
found.
 designed development: A development plan

that involves high-level insight into the


problem and more planning than incremental
development or prototype development.
 Pure function: A function that does not
modify any of the objects it receives as
arguments. Most pure functions are fruitful.

 Modifier: A function that changes one or


more of the objects it receives as arguments.
Most modifiers are void; that is, they return
None.
 Functional programming style: A style of
program design in which the majority of
functions are pure.

 invariant: A condition that should always be


true during the execution of a program.

 assert statement: A statement that checks a


condition and raises an exception if it fails.
CLASSES AND METHODS
Object-oriented features
 Programs include class and method
definitions.

 Most of the computation is expressed in


terms of operations on objects.

 Objects often represent things in the real


world, and methods often correspond to the
ways things in the real world interact.
Why methods?

 Functions : There is no obvious connection


between the class definition and the function
definitions that follow.
Methods Vs Functions
 Methods are semantically the same as
functions, but there are two syntactic
differences:

• Methods are defined inside a class definition


in order to make the relationship between
the class and the method explicit.

•The syntax for invoking a method is different


from the syntax for calling a function.
Printing objects
class Time:
"""Represents the time of day."""

def print_time(time):
print('%.2d:%.2d:%.2d' % (time.hour, time.minute,
time.second))

To call this function, you have to pass a Time object as an


argument:
>>> start = Time()
>>> start.hour = 9
>>> start.minute = 45
>>> start.second = 00
>>> print_time(start)
09:45:00
Method
class Time:
def print_time(time):
print('%.2d:%.2d:%.2d' %
(time.hour, time.minute,
time.second))
There are two ways to call print_time
>>> Time.print_time(start)
09:45:00
In this use of dot notation, Time is the name of the
class, and print_time is the name of the method.
start is passed as a parameter. (less common)

>>> start. Print_time()


09:45:00
print_time is the name of the method (again), and
start is the object the method is invoked on, which
is called the subject.
The syntax for a function call,
print_time(start), suggests that the function is
the active agent.
Ex:“Hey print_time! Here’s an object for you to
print.”

 In object-oriented programming, the objects


are the active agents.

Ex:“Hey start! Please print yourself.”


Another example
# inside class Time:
def increment(self, seconds):
seconds += self.time_to_int()
return int_to_time(seconds)

This version assumes that time_to_int is written


as a method. Also, note that it is a pure function,
not a modifier.
 A positional argument is an argument that
doesn’t have a parameter name; that is, it is
not a keyword argument.

 In this function call:

 sketch(parrot, cage, dead=True)

 parrot and cage are positional, and dead is a


keyword argument.
More complex example
>>> start.print_time()
09:45:00
>>> end = start.increment(1337)
>>> end.print_time()
10:07:17
# inside class Time:
def is_after(self, other):
return self.time_to_int() >
other.time_to_int()

To use this method, you have to invoke it on one


object and pass the other as an argument:

>>> end.Is_after(start)
True
The __init_ _ method
 The init method (short for “initialization”) is a special
method that gets invoked when an object is
instantiated. Its full name is __init__.

 # inside class Time:


def __init__(self, hour=0,minute=0,second=0):
self.hour = hour
self.minute = minute
self.second = second

It is common for the parameters of __init__ to have the


same names as the attributes. The Statement stores the
value of the parameter hour as an attribute of self.
self.hour = hour
The parameters are optional, so if you call Time
with no arguments, you get the default
values

>>> time = Time()


>>> time.print_time()
00:00:00
If you provide one argument, it overrides hour:
>>> time = Time (9)
>>> time.print_time()
09:00:00

If you provide two arguments, they override


hour and minute.
>>> time = Time(9, 45)
>>> time.print_time()
09:45:00

 And if you provide three arguments, they


override all three default values.
The __str__ method
 __str__ is a special method, like __init__, that is
supposed to return a string representation of an object.

 For example, here is a str method for Time objects:

# inside class Time:


def __str__(self):
return '%.2d:%.2d:%.2d' % (self.hour, self.minute,

self.second)

When you print an object, Python invokes the str method:


>>> time = Time(9, 45)
>>> print(time)
09:45:00
To write a new class, always start by
writing __init__, which makes it easier
to instantiate objects, and __str__,
which is useful for debugging.
Operator overloading
 By defining other special methods, you can
specify the behavior of operators on
programmer-defined types.

 For example, if you define a method named


__add__ for the Time class, you can use the +
operator on Time objects.
# inside class Time:

def __add__(self, other):


seconds = self.time_to_int() + other.time_to_int()
return int_to_time(seconds)

And we can use it as:


>>> start = Time(9, 45)
>>> duration = Time(1, 35)
>>> print(start + duration)
11:20:00
 Changing the behavior of an operator so that
it works with programmer-defined types is
called operator overloading.

 For every operator in Python there is a


corresponding special method, like __add__.
Operator overloading
Type-based dispatch
# inside class Time:
def __add__(self, other):
if isinstance(other, Time):
return self.add_time(other)
else:
return self.increment(other)
def add_time(self, other):
seconds = self.time_to_int() + other.time_to_int()
return int_to_time(seconds)
def increment(self, seconds):
seconds += self.time_to_int()
return int_to_time(seconds)
>>> start = Time(9, 45)
>>> duration = Time(1, 35)
>>> print(start + duration)
11:20:00
>>> print(start + 1337)
10:07:17

>>> print(1337 + start)


TypeError: unsupported operand type(s) for +:
'int' and 'instance'
# inside class Time:
def __radd__(self, other):
return self.__add__(other)
And here’s how it’s used:

>>> print(1337 + start)


10:07:17
Polymorphism
def histogram(s):
d = dict()
for c in s:
if c not in d:
d[c] = 1
else:
d[c] = d[c]+1
return d
This function also works for lists, tuples, and
even dictionaries, as long as the elements of
s are hashable, so they can be used as keys in
d.
>>> t = ['spam', 'egg', 'spam', 'spam', 'bacon',

'spam']
>>> histogram(t)
{'bacon': 1, 'egg': 1, 'spam': 4}
Since Time objects provide an add method,
they work with sum:
>>> t1 = Time(7, 43)
>>> t2 = Time(7, 41)
>>> t3 = Time(7, 37)
>>> total = sum([t1, t2, t3])
>>> print(total)
23:01:00
The best kind of polymorphism is the
unintentional kind, where you discover that a
function you already wrote can be applied to a
type you never planned for.
Debugging
 It is legal to add attributes to objects at any
point in the execution of a program, but if
you have objects with the same type that
don’t have the same attributes, it is easy to
make mistakes.

 It is considered a good idea to initialize all of


an object’s attributes in the init method.
 Another way to access attributes is the built-
in function vars, which takes an object and
returns a dictionary that maps from attribute
names (as strings) to their values:
>>> p = Point(3, 4)
>>> vars(p)
{'y': 4, 'x': 3}
 For purposes of debugging, you might find it
useful to keep this function handy:

def print_attributes(obj):
for attr in vars(obj):
print(attr, getattr(obj, attr))

 print_attributes traverses the dictionary and


prints each attribute name and its
corresponding value.

 The built-in function getattr takes an object


and an attribute name (as a string) and
returns the attribute’s value.
Interface and implementation
 One of the goals of object-oriented design is
to make software more maintainable, which
means that you can keep the program
Working when other parts of the system
change, and modify the program to meet new
requirements.
 For example, in this chapter we developed a
class that represents a time of day. Methods
provided by this class include time_to_int,
is_after, and add_time.

 We could implement those methods in several


ways. The details of the implementation
depend on how we represent time. In this
chapter, the attributes of a Time object are
hour, minute, and second.
 As an alternative, we could replace these attributes
with a single integer representing the number of
seconds since midnight. This implementation
would make some methods, like is_after, easier to
write, but it makes other methods harder.

 After you deploy a new class, you might discover a


better implementation. If other parts of the
program are using your class, it might be time-
consuming and error-prone to change the
interface.

 But if you designed the interface carefully, you can


change the implementation without changing the
interface, which means that other parts of the
program don’t have to change
GLOSSORY
 Object-oriented language: A language that provides

features, such as programmer defined types and


methods, that facilitate object-oriented
programming.

 Object-oriented programming: A style of


programming in which data and the operations that
manipulate it are organized into classes and
methods.

 method: A function that is defined inside a class


definition and is invoked on instances of that class.
 Subject: The object a method is invoked on.
 Positional argument: An argument that does not

include a parameter name, so it is not a keyword


argument.
 Operator overloading: Changing the behavior of an

operator like + so it works with a programmer-


defined type.
 Type-based dispatch: A programming pattern that

checks the type of an operand and invokes different


functions for different types.
 Polymorphic: Pertaining to a function that can work

with more than one type.


Thank
you

You might also like