0% found this document useful (0 votes)
19 views28 pages

Python 1st Year BPLCK205B Module 5

The document discusses the concepts of classes and objects in Python, including how to define custom types, instantiate objects, and use attributes and methods. It covers object mutability, copying objects, and the importance of pure functions versus modifiers. Additionally, it introduces object-oriented programming features such as the init method, operator overloading, and polymorphism.

Uploaded by

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

Python 1st Year BPLCK205B Module 5

The document discusses the concepts of classes and objects in Python, including how to define custom types, instantiate objects, and use attributes and methods. It covers object mutability, copying objects, and the importance of pure functions versus modifiers. Additionally, it introduces object-oriented programming features such as the init method, operator overloading, and polymorphism.

Uploaded by

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

Classes and

Functions

Classes Inheritance
and
objects Module 5

Classes and
Methods
Classes
and
objects
Programmer-defined types
• We have used many of Python’s built-in types; now we are going to define a new type.
• As an example, we will create a type called Point that represents a point in two
dimensional space.
• 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.
class Point:
"""Represents a point in 2-D space."""
>>> blank = Point()
Creating a new object is called instantiation, and the object is an instance of the class.
Attributes
• You can assign values to an instance using dot notation:
>>> blank.x = 3.0
>>> blank.y = 4.0

You can read the value of an attribute using the same syntax:
>>> blank.y You can pass an instance as an
4.0 argument in the usual way. For
>>> x = blank.x example:
>>> x def print_point(p):
3.0 print('(%g, %g)' % (p.x, p.y))
You can use dot notation as part of any expression. For example:
>>> distance = math.sqrt(blank.x**2 + blank.y**2)
>>> distance
5.0
Rectangles
• Sometimes it is obvious what the attributes of an object should be, but other times you
have to make decisions.
• For example, imagine you are designing a class to represent rectangles. What attributes
would you use to specify the location and size of a rectangle
• There are at least two possibilities:
• You could specify one corner of the rectangle (or the center), the width, and the
height.
• You could specify two opposing corners.
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
• Functions can return instances.
>>> center = find_center(box)
def find_center(rect): >>> print_point(center)
p = Point() (50, 100)
p.x = rect.corner.x + rect.width/2
p.y = rect.corner.y + rect.height/2
return p
Objects are mutable
• You can change the state of an object by making an assignment to one of its attributes.
• For example, to change the size of a rectangle without changing its position, you can modify the
values of width and height:
box.width = box.width + 50
box.height = box.height + 100

def grow_rectangle(rect, dwidth, dheight):


rect.width += dwidth
rect.height += dheight
Here is an example that demonstrates the effect:
>>> 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 >>> print_point(p1)
(3, 4)
>>> p1.y = 4.0
>>> print_point(p2)
>>> import copy (3, 4)
>>> p2 = copy.copy(p1) >>> p1 is p2
False
Copying cont….
• 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
• Fortunately, the copy module provides a method named deepcopy that copies not only
the object but also the objects it refers to, and the objects they refer to, and so on.
>>> box3 = copy.deepcopy(box)
>>> box3 is box
False
>>> box3.corner is box.corner
False
Exercise
• Exercise 1
• Write a definition for a class named Circle with attributes center and radius, where center
is a Point object and radius is a number. Instantiate a Circle object that represents a circle
with its center at (150, 100) and radius 75.
• Write a function named point_in_circle that takes a Circle and a Point and returns True if
the Point lies in or on the boundary of the circle.
• Write a function named rect_in_circle that takes a Circle and a Rectangle and returns True
if the Rectangle lies entirely in or on the boundary of the circle.
• Write a function named rect_circle_overlap that takes a Circle and a Rectangle and returns
True if any of the corners of the Rectangle fall inside the circle.
Classes
and
functions
Time
• we’ll define a class called Time that records the time of day.
class Time:
"""Represents the time of day.
attributes: hour, minute, second
""“

time = Time()
time.hour = 11
time.minute = 59
time.second = 30
Pure functions
• two kinds of functions: pure functions and modifiers
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
• The function creates a new Time object, initializes its attributes, and returns a reference to
the new object. This is called a pure function.
• Code on 156 & 157
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
• The development plan used here is called “prototype and patch”.
• For each function, we wrote a 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.
• But incremental corrections can generate code that is unnecessarily complicated.
• An alternative is designed development, in which high-level insight into the problem can
make the programming much easier. In this case, the insight is that a Time object is really
a three-digit number in base 60
Classes and methods
Object-oriented features
• Python is an object-oriented programming language, which means that it provides
features that support object-oriented programming, which has these defining
characteristics:
• 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.
• a method is a function that is associated with a particular class
• 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 make print_time a method, all we have to do is move the function definition inside the class
definition.
class Time:
def print_time(time):
print('%.2d:%.2d:%.2d' % (time.hour, time.minute, time.second))
• Now there are two ways to call print_time. The first (and less common) way is to use function
syntax:
>>> Time.print_time(start)
• The second (and more concise) way is to use method syntax:
>>> start.print_time()
Printing objects cont….
• Inside the method, the subject is assigned to the first parameter, so in this case start is
assigned to time.

• By convention, the first parameter of a method is called self, so it would be more common
to write print_time like this:
class Time:
def print_time(self):
print('%.2d:%.2d:%.2d' % (self.hour, self.minute, self.second))
• The reason for this convention is an implicit metaphor:
• The syntax for a function call, print_time(start), suggests that the function is the
active agent. It says something like, “Hey print_time! Here’s an object for you to
print.”
• In object-oriented programming, the objects are the active agents. A method
invocation like start.print_time() says “Hey start! Please print yourself.”
As an exercise, rewrite time_to_int as a method.
Another example
• Here’s a version of increment rewritten as a method:
# inside class Time:
def increment(self, seconds):
seconds += self.time_to_int()
return int_to_time(seconds)

• Here’s how you would invoke increment:


>>> start.print_time()
09:45:00
>>> end = start.increment(1337)
>>> end.print_time()
10:07:17
A more complicated example
• Rewriting is_after is slightly more complicated because it takes two Time objects as
parameters.
# 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.
# inside class Time:
def __init__(self, hour=0, minute=0, second=0):
self.hour = hour
self.minute = minute
self.second = second

• 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
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
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 here is how you could use it:
>>> start = Time(9, 45)
>>> duration = Time(1, 35) Changing the behavior of an operator so
that it works with programmer-defined
>>> print(start + duration)
types is called operator overloading.
11:20:00
Type-based dispatch
• you also might want to add an integer to a Time object. The following is a version of
__add__ that checks the type of other and invokes either add_time or increment:
# 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)
Type-based dispatch cont….
• This operation is called a type-based dispatch because it dispatches the computation to
different methods based on the type of the arguments.
• Unfortunately, this implementation of addition is not commutative. If the integer is the
first operand, you get
>>> print(1337 + start)
TypeError: unsupported operand type(s) for +: 'int' and 'instance‘
• But there is a clever solution for this problem: the special method __radd__, which stands
for “right-side add”.
• This method is invoked when a Time object appears on the right side of the + operator.
# inside class Time:
def __radd__(self, other):
return self.__add__(other)
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
• that work with several types are called polymorphic.
• Polymorphism can facilitate code reuse.

You might also like