0% found this document useful (0 votes)
152 views16 pages

BPLCK105B-205B-module-5-pdf

Thji67i

Uploaded by

patilanjali526
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)
152 views16 pages

BPLCK105B-205B-module-5-pdf

Thji67i

Uploaded by

patilanjali526
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/ 16

‭Module – 5‬

‭Classes and Objects:‬


‭Programming defined types:‬

‭ ython has a lot of built-in data types and we have used many of those types. Now we will try to‬
P
‭define our own data type that is called the user-defined (Programmer-defined) data type.‬

‭ ‬‭Example:‬

‭To understand how to create a user-defined data type, we consider an example, where we will create a‬
‭new type called Point that represents a point in 2-dimensional space.‬

I‭ n mathematical terms, the coordinates of a point are written in parentheses with a comma separating‬
‭the coordinates.‬
‭For example, (10, 10) represents the point with x coordinate value is 10 and y is 10 and in general (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:‬

‭ .‬‭First, we could have stored the coordinates separately‬‭in two variables, say x and y.‬‭2.‬‭Second, we‬
1
‭could have stored the coordinates as elements in a list data structure or tuple data structure.‬
‭3.‬‭Third, we could have created a new type to represent‬‭points as objects.‬

‭A user-defined or programmer-defined type is also‬‭called a class.‬

‭The syntax of the class definition is:‬

‭class Point:‬

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

‭ he header indicates that the new class is created with the name Point. The body of the class is a‬
T
‭string that explains‬
‭what the class is defined for. You can also add variables and methods inside a class.‬

‭ o create an object also called an instance of Point, you call Point as if it were a function.‬
T
‭Creating a new object (instance) is called instantiation, and the object is an instance of the‬
‭class.‬

‭blank = Point()‬
‭Attributes‬

‭ ne‬ ‭can‬ ‭assign‬ ‭values‬ ‭to‬ ‭an‬ ‭instance‬ ‭using‬ ‭dot‬ ‭notation.‬ ‭The‬ ‭syntax‬ ‭is‬ ‭similar‬ ‭to‬ ‭the‬ ‭syntax‬ ‭for‬
O
‭selecting‬ ‭a‬ ‭variable‬ ‭from‬ ‭a‬ ‭module,‬ ‭such‬ ‭as‬ ‭math.pi‬‭or‬‭string.whitespace.‬‭Here‬‭we‬‭have‬‭created‬‭two‬
‭elements‬ ‭of‬ ‭an‬ ‭object‬ ‭and‬ ‭assigned‬ ‭values‬ ‭to‬ ‭the‬ ‭elements‬ ‭of‬ ‭an‬ ‭object.‬ ‭These‬ ‭elements‬ ‭are‬ ‭called‬
‭attributes of objects.‬
‭ he state diagram that shows an object (instance) and its associated attributes are called an object‬
T
‭diagram which is shown below.‬
‭blank.x = 3.0‬
‭blank.y = 4.0‬

‭ oint Object‬
P
‭The value of an element of an object can be displayed as shown below example. The two syntaxes are‬
‭shown with and without using a format specifiers.‬

p‭ rint ('The value of element x is: ',blank.x)‬


‭print ('The value of element y is: ',blank.y)‬

‭ utput‬
O
‭The value of element x is: 3.0‬
‭The value of element y is: 4.0‬

‭print ('The value of element x is %g \nThe value of element y is %g' % (blank.x, blank.y))‬

‭ utput:‬
O
‭The value of element x is 3‬
‭The value of element y is 4‬

‭Rectangles‬

‭ ometimes‬‭it‬‭is‬‭obvious‬‭what‬‭the‬‭attributes‬‭of‬‭an‬‭object‬‭should‬‭be,‬‭but‬‭other‬‭times‬‭you‬‭have‬‭to‬‭make‬
S
‭decisions.‬ ‭For‬ ‭example,‬ ‭imagine‬ ‭you‬ ‭want‬ ‭to‬ ‭design‬ ‭a‬ ‭class‬ ‭to‬ ‭represent‬ ‭rectangles.‬ ‭What‬ ‭are‬ ‭the‬
‭attributes‬ ‭you‬ ‭use‬ ‭to‬ ‭specify‬ ‭the‬ ‭corner‬ ‭of‬ ‭the‬‭rectangle‬‭and‬‭the‬‭size‬‭of‬‭a‬‭rectangle?‬‭assume‬‭that‬‭the‬
‭rectangle is either vertical or horizontal.‬

‭ here are at least two possibilities:‬


T
‭You can specify one corner of the rectangle (or the center) using point, the width, and the height.‬
‭You can specify two-point to represent opposite corners.‬

.‭‬
‭Syntax:‬
‭class Rectangle:‬
‭"""Represents a rectangle attributes: width, height, corner."""‬
‭⮚‬‭The docstring lists the attributes: width and height are numbers; corner is a Point object that‬
‭specifies the lower-left corner.‬

‭⮚‬‭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‬
‭ he expression box.corner.x means, “Go to the object box refers to and select the attribute‬‭named‬
T
‭corner; then go to that object and select the attribute named x.”‬

‭ igure 15.2 shows the state of this object. An object that is an attribute of another object is‬
F
‭embedded‬‭.‬

‭Instances as return values‬

‭ unctions can return instances. For example, find_center takes a Rectangle as an argu‬‭ment and‬
F
‭returns a Point That contains the coordinates of the center of the Rectangle:‬

‭def find_center(rect):p = Point()‬


‭p.x = rect.corner.x + rect.width/2‬
‭p.y = rect.corner.y + rect.height/2return p‬
‭example that passes box as an argument and assigns the resulting Point to‬‭center:‬
‭>>> center = find_center(box)‬
‭>>> print_point(center)(50, 100)‬

‭Objects are mutable‬


‭ ou can change the state of an object by making an assignment to one of its attributes. For‬‭example,‬
Y
‭to change the size of a rectangle without changing its position, you can modify the values of width‬
‭and height:‬
b‭ ox.width = box.width + 50 box.height = box.height + 100‬
‭For example, grow_rectangle takes a Rectangle object and two numbers, dwidth and dheight, and‬
‭adds the numbers to the width and height of the rectangle:‬
‭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)‬
‭Inside the function, rect is an alias for box, so when the function modifies rect, box changes.‬
‭ s‬ ‭an‬ ‭exercise,‬ ‭write‬ ‭a‬ ‭function‬ ‭named‬ ‭move_rectangle‬ ‭that‬ ‭takes‬ ‭a‬ ‭Rectangle‬ ‭and‬ ‭two‬ ‭numbers‬
A
‭named‬‭dx‬‭and‬‭dy.‬‭It‬‭should‬‭change‬‭the‬‭location‬‭of‬‭the‬‭rectangle‬‭by‬‭adding‬‭dx‬‭to‬ ‭the‬‭x‬‭coordinate‬‭of‬
‭cornerand adding dyto the ycoordinate of corner.‬

‭Copying‬
‭ liasing‬‭can‬‭make‬‭a‬‭program‬‭difficult‬‭to‬‭read‬‭because‬‭changes‬‭in‬‭one‬‭place‬‭might‬‭have‬‭unexpected‬
A
‭effects in another place. It is hard to keep track of all the variables that might refer to a given object.‬
‭ opying an object is often an alternative to aliasing. The copy module contains a function called copy‬
C
‭that can duplicate any object:‬
‭>>> p1 = Point()‬
‭>>> p1.x = 3.0‬
‭>>> p1.y = 4.0‬

‭>>> import copy‬


‭>>> p2 = copy.copy(p1)‬
‭p1and p2 contain the same data, but they are not the same Point.‬
‭>>> print_point(p1)(3, 4)‬
‭>>> print_point(p2)(3, 4)‬
‭>>> p1 is p2False‬
‭>>> p1 == p2‬
‭False‬

‭Figure 15.3: Object diagram.‬

‭ he is operator indicates that p1 and p2 are not the same object, which is what we ex- pected. But you‬
T
‭might have expected == to yield True because these points contain the same‬‭data. In that case, you‬
‭will be disappointed to learn that for instance, the default‬‭behavior of the == operator is the same as‬
t‭he is operator; it checks object identity, not‬‭object equivalence. That’s because for programmer‬
‭defined types, Python doesn’t know what should be considered equivalent. At least, not yet.‬
‭If you use copy.copy to duplicate a Rectangle, you will find that it copies the Rectangle object but‬
n‭ ot the embedded Point.‬
‭>>> box2 = copy.copy(box)‬
‭>>> box2 is boxFalse‬
‭>>> box2.corner is box.cornerTrue‬
‭ igure 15.3 shows what the object diagram looks like. This operation is called a‬‭shallow copy‬
F
‭because it copies the object and any references it contains, but not the embedded objects.‬
‭ he copy module provides a method named deepcopythat copies not only the object but also the‬
T
‭objects it refers to, and the objects‬‭they‬‭refer to, and so on. You will not be surprised to learn that‬
‭this operation is called a‬‭deep copy‬‭.‬
‭>>> box3 = copy.deepcopy(box)‬
‭>>> box3 is boxFalse‬
‭>>> box3.corner is box.cornerFalse‬
‭box3 and box are completely separate objects.‬
‭Classes and functions‬

‭Time:‬

‭ s another example of a programmer-defined type, we’ll define a class called Time that‬‭records‬
A
‭the time of day. The class definition looks like this:‬
‭class Time:‬
‭"""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‬
‭The state diagram for the Timeobject looks like Figure 16.1.‬
‭Pure Functions:‬

T‭ he two kinds of functions: pure functions and modifiers. They also demonstrate a development plan‬
‭I’ll call‬‭prototype and patch‬‭, which is a way of tackling‬‭a complex problem by starting with a simple‬
‭prototype and incrementally dealing with the complications.‬
‭Here is a simple prototype of add_time:‬
d‭ ef add_time(t1, t2):‬
‭sum = Time()‬
s‭ um.hour = t1.hour + t2.hour‬
‭sum.minute = t1.minute + t2.minute‬
‭sum.second = t1.second + t2.second‬
‭return sum‬
‭ he function creates a new Time object, initializes its attributes, and returns a reference to the‬
T
‭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.‬
‭ o‬ ‭test‬ ‭this‬ ‭function,‬ ‭we‬ ‭create‬ ‭two‬ ‭Time‬ ‭objects:‬ ‭start‬ ‭contains‬ ‭the‬‭start‬‭time‬‭of‬‭a‬‭movie,‬‭like‬
T
‭Monty‬‭Python‬‭and‬‭the‬‭Holy‬‭Grail‬‭,‬‭and‬‭duration‬‭contains‬‭the‬‭run‬‭time‬‭of‬‭the‬‭movie,‬‭which‬‭is‬‭one‬
‭hour 35 minutes.‬

a‭ dd_timefigures 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‬
‭ he‬ ‭result,‬ ‭10:80:00‬ ‭might‬ ‭not‬ ‭be‬ ‭what‬ ‭you‬ ‭were‬ ‭hoping‬ ‭for.‬ ‭The‬ ‭problem‬ ‭is‬ ‭that‬ ‭this‬
T
‭function‬ ‭does‬ ‭not‬ ‭deal‬ ‭with‬ ‭cases‬ ‭where‬ ‭the‬ ‭number‬ ‭of‬ ‭seconds‬ ‭or‬ ‭minutes‬ ‭adds‬ ‭up‬ ‭to‬
‭more‬‭than‬‭sixty.‬‭When‬‭that‬‭happens,‬‭we‬‭have‬‭to‬‭“carry”‬‭the‬‭extra‬‭seconds‬‭into‬‭the‬‭minute‬
‭column or the extra minutes into the hour column.‬
‭Here’s an improved version‬
‭def add_time(t1, t2):‬
‭sum = Time()‬

s‭ um.hour = t1.hour + t2.hour‬


‭sum.minute = t1.minute +‬
‭t2.minute sum.second = t1.second‬
‭+ t2.secondreturn sum‬

‭Modifiers:‬
‭ ometimes it is useful for a function to modify the objects it gets as parameters. In that case, the‬
S
‭changes are visible to the caller. Functions that work this way are called‬‭modifiers‬‭.‬
i‭ncrement, which adds a given number of seconds to a Timeobject, 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‬


‭time.hour += 1‬

‭The first line performs the basic operation; the remainder deals with the special cases we saw‬
b‭ efore.‬
‭Is this function correct? What happens if the second is much greater than sixty?‬
I‭ n that case, it is not enough to carry once; we have to keep doing it until the time.second is less‬
‭than sixty. One solution is to replace the if statements with while statements. That would make‬
‭the function correct, but not very efficient. As an exercise, write a correct version of increment‬
‭that doesn’t contain any loops.‬
‭ nything that can be done with modifiers can also be done with pure functions. In fact, some‬
A
‭programming languages only allow pure functions. There is some evidence that‬‭programs that‬
‭use pure functions are faster to develop and less error-prone than programs that use modifiers.‬
‭But modifiers are convenient at times, and functional programs tend to‬‭be less efficient.‬
‭Prototyping versus planning‬
‭ he‬‭development‬‭plan‬‭I‬‭am‬‭demonstrating‬‭is‬‭called‬‭“prototype‬‭and‬‭patch”.‬‭For‬‭each‬‭func-tion,‬‭I‬
T
‭wrote‬‭a‬‭prototype‬‭that‬‭performed‬‭the‬‭basic‬‭calculation‬‭and‬‭then‬‭tested‬‭it,‬‭patching‬‭errors‬‭along‬
‭the way.‬
‭ n alternative is‬‭designed development‬‭, in which high-level‬‭insight into the problem can make‬
A
‭the programming much easier.‬
‭In this case, the insight is that a Time object is really a three-digit number in base 60 (see‬
‭http://en.wikipedia.org/wiki/Sexagesimal). The second attribute is the “ones column”, the‬
‭minute attribute is the “sixties column”, and the hour attribute is the “thirty-six hundredths‬
‭column”.‬

‭ hen we wrote add_time and increment, we were effectively doing addition in base 60,‬
W
‭which is why we had to carry from one column to the next.‬
‭ his‬ ‭observation‬ ‭suggests‬ ‭another‬ ‭approach‬ ‭to‬ ‭the‬ ‭whole‬ ‭problem—we‬ ‭can‬ ‭convert‬ ‭Time‬
T
‭objects‬‭to‬‭integers‬‭and‬‭take‬‭advantage‬‭of‬‭the‬‭fact‬‭that‬‭the‬‭computer‬‭knows‬‭how‬‭to‬‭do‬‭integer‬
‭arithmetic.‬
‭Here is a function that converts Times to integers:‬
‭def time_to_int(time):‬
‭ inutes = time.hour * 60 + time.minute‬
m
‭seconds = minutes * 60 + time.second‬
‭return seconds‬
‭And here is a function that converts an integer to a Time (recall that divmod divides‬
t‭he first argument by the second and returns the quotient and remainder as a tuple).‬
d‭ ef‬
‭int_to_time(seconds):‬
‭time = Time()‬
‭ inutes, time.second = divmod(seconds, 60)‬
m
‭time.hour, time.minute = divmod(minutes, 60)‬
‭return time‬
‭ ou might have to think a bit, and run some tests, to convince yourself that these‬
Y
‭functions‬‭are correct. One way to test them is to‬‭check that‬
‭time_to_int(int_to_time(x)) == x for many values of x. This is an example of a‬
‭consistency check.‬
‭ nce you are convinced they are correct, you can use them to rewrite‬
O
‭add_time:def add_time(t1, t2):‬

‭seconds = time_to_int(t1) + time_to_int(t2)‬


‭return int_to_time(seconds)‬
‭Classes and methods‬

‭ bject-oriented features:‬
O
‭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.‬

‭ ethods‬‭:‬ ‭A‬ ‭method‬ ‭is‬ ‭a‬ ‭function‬ ‭that‬ ‭is‬ ‭associated‬ ‭with‬ ‭a‬ ‭particular‬ ‭class.‬ ‭We‬
M
‭have‬‭seen‬‭methods‬‭for‬‭strings,‬‭lists,‬‭dictionaries‬‭and‬‭tuples.‬‭In‬‭this‬‭chapter,‬‭we‬ ‭will‬
‭define methods for programmer-defined types.‬
‭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.‬

I‭ n‬ ‭the‬‭next‬‭few‬‭sections,‬‭we‬‭will‬‭take‬‭the‬‭functions‬‭from‬‭the‬‭previous‬‭two‬‭chapters‬
‭and‬ ‭transform‬ ‭them‬ ‭into‬ ‭methods.‬ ‭This‬ ‭transformation‬ ‭is‬ ‭purely‬ ‭mechanical;‬ ‭you‬
‭can‬ ‭do‬ ‭it‬‭by‬‭following‬‭a‬‭sequence‬‭of‬‭steps.‬‭If‬‭you‬‭are‬‭comfortable‬‭converting‬‭from‬
‭one‬‭form‬‭to‬‭another,‬‭you‬‭will‬‭be‬‭able‬‭to‬‭choose‬‭the‬‭best‬‭form‬‭for‬‭whatever‬‭you‬‭are‬
‭doing.‬

‭Printing objects‬
‭We define a class named Time by using a function‬‭named‬‭print_time:‬
‭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 Timeobject as an argument:‬
‭>>> start = Time()‬
‭>>> start.hour = 9‬

‭>>> start.minute = 45‬


‭>>> start.second = 00‬
‭ >> print_time(start)‬
>
‭09:45:00‬
‭To make print_timea method, all we have to do is move the function definition‬
‭inside the class definition. Notice the change in indentation.‬
‭class Time:‬
‭def print_time(time):‬
‭'‬ ‭'‬
‭print(‬ ‭%.2d:%.2d:%.2d‬ ‭% (time.hour, time.minute,‬‭time.second))‬
‭ here are two ways to call print_time. The first (and less common) way is to use‬
T
‭function syntax:‬
‭ >> Time.print_time(start)‬
>
‭09:45:00‬
I‭ n this use of dot notation, Time is the name of the class, and print_time is the‬
‭name of the method‬‭. startis passed as a parameter.‬
‭The second (and more concise) way is to use method syntax:‬
‭ >> start.print_time()‬
>
‭09:45:00‬
I‭ n this use of dot notation, print_time is the name of the method (again), and start is the‬
‭object the method is invoked on, which is called the‬‭subject‬‭. Just as the subject of a‬
‭sentence is what the sentence is about, the subject of a method invocation is what the‬
‭method is about.‬

I‭ nside the method, the subject is assigned to the first parameter, so in this case start is‬
‭assigned to time.‬

‭ y convention, the first parameter of a method is called self, so it would be more common‬
B
‭to write print_timelike 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‬
a‭ ctive‬ ‭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‬


‭invoca-tion like start.print_time()says “Hey start! Please print yourself.”‬

‭ his‬‭change‬‭in‬‭perspective‬‭might‬‭be‬‭more‬‭polite,‬‭but‬‭it‬‭is‬‭not‬‭obvious‬‭that‬‭it‬‭is‬‭useful.‬‭In‬‭the‬
T
‭examples‬‭we‬‭have‬‭seen‬‭so‬‭far,‬‭it‬‭may‬‭not‬‭be.‬‭But‬‭sometimes‬‭shifting‬‭responsibility‬‭from‬‭the‬
‭functions‬ ‭onto‬ ‭the‬‭objects‬‭makes‬‭it‬‭possible‬‭to‬‭write‬‭more‬‭versatile‬‭functions‬‭(or‬‭methods),‬
‭and makes it easier to maintain and reuse code.‬
‭ s‬‭an‬‭exercise,‬‭rewrite‬‭time_to_int‬‭(from‬‭Section‬‭16.4)‬‭as‬‭a‬‭method.‬‭You‬‭might‬‭be‬‭tempted‬
A
‭to‬ ‭rewrite‬ ‭int_to_time‬ ‭as‬ ‭a‬ ‭method,‬ ‭too,‬ ‭but‬ ‭that‬ ‭doesn’t‬ ‭really‬ ‭make‬ ‭sense‬ ‭because‬ ‭there‬
‭would be no object to invoke it on.‬

‭Another example:‬

‭Here’s a version of increment rewritten as a method:‬


‭# inside class Time:‬

d‭ ef increment(self, seconds): seconds +=‬


‭self.time_to_int()return int_to_time(seconds)‬
‭ his version assumes that time_to_int is written as a method. Also, note that it is a pure‬
T
‭function, not a modifier.‬
‭Here’s how you would invoke increment:‬
‭ >> start.print_time()‬
>
‭09:45:00‬
‭>>> end = start.increment(1337)‬
‭>>> end.print_time()10:07:17‬

‭ he subject, start, gets assigned to the first parameter, self. The argument, 1337, gets‬
T
‭assigned to the second parameter, seconds.‬
‭ his mechanism can be confusing, especially if you make an error. For example,‬
T
‭if you invoke increment with two arguments, you get:‬
‭ >> end = start.increment(1337, 460)‬
>
‭TypeError: increment() takes 2 positional arguments but 3 were given‬
‭The error message is initially confusing, because there are only two arguments in‬
p‭ arentheses. But the subject is also considered an argument, so all together that’s three.‬
‭ y the way, a‬‭positional argument‬‭is an argument that‬‭doesn’t have a parameter‬
B
‭name;that is, it is not a keyword argument. In this function call:‬
‭sketch(parrot, cage, dead=True)‬
‭parrotand cageare positional, and deadis a keyword argument.‬

‭A more complicated example:‬

‭ ewriting is slightly more complicated because it takes two Time objects as parameters.‬
R
‭In this case it is conventional to name the first parameter self‬‭and the second parameter‬
‭other:‬
‭# 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‬
‭One nice thing about this syntax is that it almost reads like English: “end is after start?”‬

‭The init method:‬


‭ he‬‭init‬‭method‬‭(short‬‭for‬‭“initialization”)‬‭is‬‭a‬‭special‬‭method‬‭that‬‭gets‬‭invoked‬‭when‬ ‭an‬
T
‭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:‬
‭# inside class Time:‬
‭def‬‭__init__(self, hour=0, minute=0, second=0):‬
‭self.hour = hour‬
s‭ elf.minute = minute‬
‭self.second = second‬
I‭ t is common for the parameters of __init__ to have the same names as the‬
‭attributes. The Statement‬
‭self.hour = hour‬
‭stores the value of the parameter hour as an attribute of self.‬
‭ he parameters are optional, so if you call Time with no arguments, you get the default‬
T
‭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.‬
‭ s an exercise, write an init method for the Point class that takes x and y as optional‬
A
‭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.‬
‭For example, here is a strmethod for Time objects:‬
‭# inside class Time:‬
‭def__str__(self):‬
‭'‬ ‭'‬
‭return‬ ‭%.2d:%.2d:%.2d‬ ‭% (self.hour, self.minute,‬‭self.second)‬

‭When you printan object, Python invokes the strmethod:‬


‭>>> time = Time(9, 45)‬
‭ >> print(time)‬
>
‭09:45:00‬
‭Operator overloading‬
‭ y‬ ‭defining‬ ‭other‬ ‭special‬ ‭methods,‬ ‭you‬ ‭can‬ ‭specify‬ ‭the‬ ‭behavior‬ ‭of‬ ‭operators‬ ‭on‬
B
‭programmer-defined‬ ‭types.‬ ‭For‬ ‭example,‬ ‭if‬ ‭you‬ ‭define‬ ‭a‬ ‭method‬ ‭named‬ ‭__add__‬ ‭for‬ ‭the‬
‭Timeclass, you can use the +operator on Time objects.‬
‭Here is what the definition might look like:‬

‭# inside class Time:‬

‭def‬‭__add__(self, other):‬

s‭ econds = 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)‬
‭ >> print(start + duration)‬
>
‭11:20:00‬
‭Type-based dispatch:‬
I‭ n‬ ‭the‬ ‭previous‬ ‭section‬ ‭we‬ ‭added‬ ‭two‬ ‭Time‬‭objects,‬‭but‬‭you‬‭also‬‭might‬‭want‬‭to‬‭add‬‭an‬
‭integer‬ ‭to‬ ‭a‬ ‭Time‬ ‭object.‬ ‭The‬ ‭following‬ ‭is‬ ‭a‬ ‭version‬ ‭of‬ ‭__add__‬ ‭that‬ ‭checks‬ ‭the‬ ‭type‬ ‭of‬
‭otherand invokes either add_timeor 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‬


i‭nt_to_time(seconds)‬

‭def increment(self, seconds): seconds +=‬


‭self.time_to_int() return‬
‭int_to_time(seconds)‬
‭ he built-in function is instance takes a value and a class object, and returns True if the‬
T
‭value is an instance of the class.‬

I‭ f other is a Time object, __add__ invokes add_time. Otherwise it assumes that the param-‬
‭eter 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‬
‭argu-ments.‬

‭Polymorphism:‬
‭ ype-based‬ ‭dispatch‬ ‭is‬ ‭useful‬ ‭when‬ ‭it‬ ‭is‬ ‭necessary,‬ ‭but‬ ‭(fortunately)‬ ‭it‬ ‭is‬ ‭not‬ ‭always‬
T
‭necessary.‬ ‭Often‬ ‭you‬ ‭can‬ ‭avoid‬ ‭it‬ ‭by‬ ‭writing‬ ‭functions‬ ‭that‬ ‭work‬ ‭correctly‬ ‭for‬ ‭arguments‬
‭with different types.‬
‭ any‬‭of‬‭the‬‭functions‬‭we‬‭wrote‬‭for‬‭strings‬‭also‬‭work‬‭for‬‭other‬‭sequence‬‭types.‬‭For‬‭exam-‬
M
‭ple,‬ ‭in‬ ‭Section‬ ‭11.2‬ ‭we‬‭used‬‭histogram‬‭to‬‭count‬‭the‬‭number‬‭of‬‭times‬‭each‬‭letter‬‭appears‬‭in‬
‭word.‬
d‭ ef histogram(s): d =‬
‭dict() for c in s:‬
‭if c not in d:d[c] = 1‬
‭else:‬
‭d[c] = d[c]+1‬
‭return d‬
‭ his function also works for lists, tuples, and even dictionaries, as long as the elements of‬
T
‭sare 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}‬

‭ unctions‬ ‭that‬ ‭work‬ ‭with‬ ‭several‬ ‭types‬ ‭are‬ ‭called‬ ‭polymorphic‬‭.‬ ‭Polymorphism‬ ‭can‬
F
‭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 addmethod, 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‬
I‭ n general, if all of the operations inside a function work with a given type, the function‬
‭works with that type.‬
‭ he best kind of polymorphism is the unintentional kind, where you discover that a‬
T
‭function you already wrote can be applied to a type you never planned for.‬
‭Interface and implementation:‬

‭ ne‬‭of‬‭the‬‭goals‬‭of‬‭object-oriented‬‭design‬‭is‬‭to‬‭make‬‭software‬‭more‬‭maintainable,‬ ‭which‬
O
‭means‬ ‭that‬ ‭you‬‭can‬‭keep‬‭the‬‭program‬‭working‬‭when‬‭other‬‭parts‬‭of‬‭the‬‭system‬‭change,‬ ‭and‬
‭modify the program to meet new requirements.‬

‭ or example, in this chapter we developed a class that represents a time of day. Methods‬
F
‭provided by this class include time_to_int, is_after, and add_time.‬
‭ e‬ ‭could‬ ‭implement‬ ‭those‬ ‭methods‬ ‭in‬ ‭several‬ ‭ways.‬ ‭The‬ ‭details‬ ‭of‬ ‭the‬ ‭implementation‬
W
‭depend‬ ‭on‬ ‭how‬ ‭we‬ ‭represent‬ ‭time.‬ ‭In‬‭this‬‭chapter,‬‭the‬‭attributes‬‭of‬‭a‬‭Time‬‭object‬‭are‬‭hour,‬
‭minute, and second.‬
‭ s‬ ‭an‬ ‭alternative,‬ ‭we‬ ‭could‬‭replace‬‭these‬‭attributes‬‭with‬‭a‬‭single‬‭integer‬‭representing‬‭the‬
A
‭number‬ ‭of‬ ‭seconds‬ ‭since‬ ‭midnight.‬ ‭This‬ ‭implementation‬ ‭would‬ ‭make‬ ‭some‬ ‭methods,‬
‭likeis_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‬
t‭he‬‭program‬‭are‬‭using‬‭your‬‭class,‬‭it‬‭might‬‭be‬‭time-consuming‬‭and‬‭error-prone‬‭to‬‭change‬‭the‬
‭interface.‬

‭ ut if you designed the interface carefully, you can change the implementation without‬
B
‭changing the interface, which means that other parts of the program don’t have to change.‬

You might also like