MOD - 4 - Class and OBJ
MOD - 4 - Class and OBJ
MOD - 4 - Class and OBJ
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.
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.
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:
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?
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:
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.
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.
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?
increment, which adds a given number of seconds to a Time object, can be written naturally as a
modifier. Here is a rough draft:
This approach can be effective, especially if you don’t yet have a deep understanding of the
problem.
◦ 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))
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.
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.
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: