Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

MOD - 4 - Class and OBJ

Download as pdf or txt
Download as pdf or txt
You are on page 1of 43

MODULE 4

A RU N K H
A S ST. P RO F.
D E P T. O F IS E , AC HA RYA IT
Python Class and Objects
Python is an object-oriented programming language.

Almost everything in Python is an object, with its properties and methods.

A Class is like an object constructor, or a "blueprint" for creating objects.

Create a Class
To create a class, use the keyword class:
class MyClass:
x=5
User-defined types
In Python we have been using several types to store the data:
Primitive type User defined Types
Creating a new type is (a little) more
integer / long integer complicated than the other options, but it has
char advantages that will be apparent soon.

float / double A user-defined type is also called a class.


A class definition looks like this:
string
class Point(object):
Advanced types x=0
y=0
list This header indicates that the new class is a
tuple Point, which is a kind of object, which is a built-
in type
dictionaries Defining a class named Point creates a class object.
>>> print Point
<class '__main__.Point'>
Class and Objects contd.,
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()
>>> print blank
<__main__.Point instance at 0xb7e9d3ac>

The return value is a reference to a Point object, which we assign to blank.

Creating a new object is called instantiation, and the object is an instance of the class.

When you print an instance, Python tells you what class it belongs to and where it is stored in
memory
Attributes
You can assign values to an instance using dot notation:

>>> blank.x = 3.0

>>> blank.y = 4.0


The following diagram shows the result of these assignments. A state diagram that shows an
object and its attributes is called an object diagram:

The variable blank refers to a Point object, which contains


two attributes. Each attribute refers to a floating-point
number
Attributes Contd.,
You can use dot notation as part of any expression. For example:
>>> print '(%g, %g)' % (blank.x, blank.y)
(3.0, 4.0)
>>> distance = math.sqrt(blank.x**2 + blank.y**2)
>>> print(distance)
5.0
You can pass an instance as an argument in the usual way. For example:

def print_point(p): >>> print_point(blank)


print '(%g, %g)' % (p.x, p.y) (3.0, 4.0)
Rectangles
As programmer we need to understand the requirements and decide on the classes, attributes
and methods that needs to be implemented

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.
Here is the class definition:
class Rectangle(object):
"""represent a rectangle.
attributes: width, height, corner.
"""
Rectangles Contd.,
To represent a rectangle, you have to instantiate a Rectangle object and assign values to the
attributes:
box = Rectangle()
box.width = 100.0
box.height = 200.0
box.corner = Point()
box.corner.x = 0.0
box.corner.y = 0.0

The expression box.corner.x means, “Go to the object box refers to and select the attribute named
corner; then go to that object and select the attribute named x.
Instances as return values
Functions can return instances.
For example, find_center() takes a Rectangle as an argument and returns a Point that contains
the coordinates of the center of the Rectangle:

def find_center(box):
p = Point()
p.x = box.corner.x + box.width/2.0
p.y = box.corner.y + box.height/2.0
return p
Here is an example that passes box as an argument and assigns the resulting Point to center:

>>> center = find_center(box)


>>> print_point(center)
(50.0, 100.0)
Objects are mutable
A mutable object is one which can be changed after it's creation/Instantiation

We 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 >>> print(box.width)
box.height = box.width + 100 100.0
◦ We can also write functions that modify objects: >>> print(box.height)
200.0
def grow_rectangle(rect, dwidth, dheight) : >>> grow_rectangle(box, 50, 100)
rect.width += dwidth >>> print(box.width)
rect.height += dheight 150.0
>>> print(box.height)
300.0
Exercise:
Write a function named move_rectangle() that takes a Rectangle and two
numbers named dx and dy. It should change the location of the rectangle by
adding dx to the x coordinate of corner and adding dy to the y coordinate of
corner.
Copying
Aliasing can make a program difficult to read because changes in one place might have
unexpected effects in another place.

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 >>> import copy >>> print_point(p1)
>>> p1.y = 4.0 >>> p2 = copy.copy(p1) (3.0, 4.0)
>>> print_point(p2)
p1 and p2 contain the same data, but they are not the same Point (3.0, 4.0)
>>> p1 is p2
False
>>> p1 == p2
False
Copying Contd.,
If we 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

Here is what the object diagram looks like: This operation is called a shallow copy
Copying Contd.,
The copy module contains 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 This operation is called a deep copy
>>> box3.corner is box.corner
False
Excercise
Write a new version of move_rectangle() that creates and returns
a new Rectangle instead of modifying the old one.
Classes and functions
Time
As another example of a user-defined type, we’ll define a class called Time
that records the time of day. The class definition looks like this:
class Time(object):
"""represents the time of day.
attributes: hour, minute, second"""

We can create a new Time object and assign attributes for hours, minutes,
and seconds:
>>>time = Time()
>>>time.hour = 11
>>>time.minute = 59
>>>time.second = 30
Time Contd.,
The state diagram for the Time object looks like this:

Exercise: Write a function called print_time that takes a Time object and prints it in
the form hour:minute:second. Hint: the format sequence '%.2d' prints an integer
using at least two digits, including a leading zero if necessary.
Pure functions
What if a programmer needs to write two functions that add time values?

This can be done in two ways:


◦ pure functions and modifiers
tackling a complex problem can be started with a simple prototype and incrementally
dealing with the complications.
Here is a simple prototype:
def add_time(t1, t2): function creates a new Time object
sum = Time()
sum.hour = t1.hour + t2.hour This is called a pure function
sum.minute = t1.minute + t2.minute
sum.second = t1.second + t2.second
return sum
Pure Functions Contd.,
To test this function: Here’s an improved version:
>>> start = Time() def add_time(t1, t2):
>>> start.hour = 9 sum = Time()
>>> start.minute = 45 sum.hour = t1.hour + t2.hour
>>> start.second = 0 sum.minute = t1.minute + t2.minute
>>> duration = Time() sum.second = t1.second + t2.second
>>> duration.hour = 1 if sum.second >= 60:
>>> duration.minute = 35 sum.second -= 60
>>> duration.second = 0 sum.minute += 1
>>> done = add_time(start, duration) if sum.minute >= 60:
>>> print_time(done) sum.minute -= 60
10:80:00 sum.hour += 1
return sum
Modifiers
Sometimes it is useful for a function to modify the objects it gets as parameters.

Functions that work this way are called modifiers

increment, which adds a given number of seconds to a Time object, can be written naturally as a
modifier. Here is a rough draft:

def increment(time, seconds):


time.second += seconds
if time.second >= 60:
time.second -= 60
time.minute += 1
if time.minute >= 60:
time.minute -= 60 Exercise:
time.hour += 1 Write a correct version of increment that doesn’t contain any loops.
Prototyping versus planning
The development plan a programmer develops is called “prototype and patch”

This approach can be effective, especially if you don’t yet have a deep understanding of the
problem.

incremental corrections can generate code that is unnecessarily complicated—since it deals


with many special cases—and unreliable—since it is hard to know if you have found all the
errors.

An alternative is planned development

In the earlier implementation of add_time(), increment() we were effectively doing addition in


base 60, which is why we had to carry from one column to the next.
Contd.,
Here is a function that converts Times to integers: you can use them to rewrite add_time:
def time_to_int(time): def add_time(t1, t2):
minutes = time.hour * 60 + time.minute seconds = time_to_int(t1) + time_to_int(t2)
seconds = zinutes * 60 + time.second return int_to_time(seconds)
return seconds

Here is the function that converts integers to Times:


def int_to_time(seconds):
time = Time()
minutes, time.second = divmod(seconds, 60)
time.hour, time.minute = divmod(minutes, 60)
return time
Classes and Methods
Object-oriented features
Python is a programming language which provides features that support object-oriented
programming.
◦ Programs are made up of object definitions and function definitions, and most of the computation is
expressed in terms of operations on objects.

◦ Each object definition corresponds to some object or concept in the real world, and the functions
that operate on that object correspond to the ways real-world objects interact.
 For example, the Time class defined in the previous section.
Methods
So far, we have seen how to define a class, how to instantiate an object, how to modify the
attributes.

In the Time program, there is no obvious connection between the class definition and the function
definitions that follow.

This observation is the motivation for methods; 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
Consider the class Time mentioned / defined in the previous function. We had defined a function
named print_time() :
class Time(object):
"""represents the time of day.
attributes: hour, minute, second"""

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

>>> start = Time()


>>> start.hour = 9 To make print_time a method, all we have to do is move
>>> start.minute = 45 the function definition inside the class definition.
>>> start.second = 00
>>> print_time(start)
09:45:00
Printing objects Contd.,
Consider the following class definitions that contains a method print_time()
class Time(object):
“””Declare hour,minute,second”””
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)
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.

The second (and more concise) way is to use method syntax: >>> start.print_time()
09:45:00
Printing objects Contd.,
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(object):
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.
◦ In object-oriented programming, the objects are the active agents.

Exercise: Rewrite time_to_int (from Section 16.4) as a method. It is probably not appropriate to rewrite
int_to_time as a method; it’s not clear what object you would invoke it on!
Example
We have seen in the previous section that it is conventional to name the first parameter self.
What if a method needs two objects as parameter?
Consider the example of add_time() which requires two parameters ie., t1,t2 . If we need to
represent the function add_time() as a method then, we need to represent the second parameter
as other.
# inside class Time:
Consider the below example:
def add_time(self, other):
seconds = time_to_int(self) + time_to_int(other)
return int_to_time(seconds)
To use this method, you must invoke it on one object and pass the other as an argument:

>>> time1.add_time(time2)
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__ (two underscore characters, followed by init, and then two more
underscores).

An init method for the Time class might look like this: It is common for the parameters of __init__ to
have the same names as the attributes. The
# inside class Time: statement
def __init__(self, hour=0, minute=0, second=0):
self.hour = hour self.hour = hour
self.minute = minute
self.second = second stores the value of the parameter hour as an
attribute of self.
The init method
The parameters are optional, so if you call Time with no arguments, you get the default values.

>>> time = Time()


>>> time.print_time()
00:00:0
If you provide one argument, it overrides hour:
>>> time = Time (9)
>>> time.print_time()
09:00:00
f you provide two arguments, they override hour and minute.
>>> time = Time(9, 45)
>>> time.print_time() Note: And if you provide three arguments, they override all three
09:45:00 default values.
Exercise
Write an init method for the Point class that takes x and y as
optional parameters and assigns them to the corresponding
attributes.
The str method
_str__ is a special method, like __init__, that is supposed to return a string representation of an
object.

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

NOTE: When I write a new class, I almost always start by writing __init__, which makes it easier to
instantiate objects, and __str__, which is useful for debugging.
EXERCISE
Write a str method for the Point class. Create a Point object and
print it.
Operator overloading
By defining other special methods, you can specify the behavior of operators on user-defined types.

For example, if you define a method named __add__ for the Time class, you can use the + operator on
Changing the behavior of an
Time objects.
operator so that it works with
Here is what the definitionuser-defined
might look like: types is called And here is how you could use it:
# inside class Time: operator overloading
def __add__(self, other):
>>> start = Time(9, 45)
>>> duration = Time(1, 35)
seconds = self.time_to_int() + other.time_to_int() >>> print (start + duration)
return int_to_time(seconds) 11:20:00

When you apply the + operator to Time objects, Python invokes __add__. When you print the result,
Python invokes __str__.
EXCERCISE
Write an add method for the Point class.
Type-based dispatch
# inside class Time:
In the previous section we added two
def __add__(self, other):
Time objects, but you also might want if isinstance(other, Time):
to add an integer to a Time object. return self.add_time(other)
else:
The following is a version of __add__ return self.increment(other)
that checks the type of other and
invokes either. def add_time(self, other):
seconds = self.time_to_int() + other.time_to_int()
Here is what the definition might look return int_to_time(seconds)
like:
def increment(self, seconds):
seconds += self.time_to_int()
return int_to_time(seconds)
Type-based dispatch Contd.,
The built-in function isinstance takes a value and a class object, and returns True if the value is an
instance of the class.

If other is a Time object, __add__ invokes add_time. Otherwise it assumes that the parameter is a
number and invokes increment. This operation is called a type-based dispatch because it
dispatches the computation to different methods based on the type of the arguments.

Here are examples that use the + operator with different types:
>>> start = Time(9, 45) Unfortunately, this implementation of addition is not
>>> duration = Time(1, 35) commutative. If the integer is the first operand, you get
>>> print (start + duration)
11:20:00 >>> print (1337 + start)
>>> print (start + 1337) TypeError: unsupported operand type(s) for +: 'int' and 'instance'
10:07:17
Solution to add an integer with Object
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.

Here’s the definition:


# inside class Time: And here’s how it’s used:

def __radd__(self, other): >>> print (1337 + start)


return self.__add__(other) 10:07:17
Polymorphism
Type-based dispatch is useful when it is necessary, but (fortunately) it is not always necessary.
Often you can avoid it by writing functions that work correctly for arguments with different types.

Many of the functions we wrote for strings will actually work for any kind of sequence. For
example, In dictionaries we used histogram to count the number of times each letter appears in a
word.
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
Polymorphism contd.,
The function in previous slide 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

Functions that can work with several types are called polymorphic. Polymorphism can facilitate
code reuse. For example, the built-in function sum, which adds the elements of a sequence, works
as long as the elements of the sequence support addition.

Since Time objects provide an add method, they work with sum:

>>> t1 = Time(7, 43)


>>> t2 = Time(7, 41)
In general, if all of the operations inside a
>>> t3 = Time(7, 37)
function work with a given type, then the
>>> total = sum([t1, t2, t3])
function works with that type.
>>> print (total)
23:01:00
Thank You
End of Module-4

You might also like