330 likes | 539 Views
Programming for Engineers in Python. Recitation 6. Agenda. Object Oriented Programming: Old McDonald Had a Farm Time Class. Example – Old McDonald.
E N D
Programming for Engineers in Python Recitation 6
Agenda • Object Oriented Programming: • Old McDonald Had a Farm • Time Class
Example – Old McDonald • __str__ - Called by the str() built-in function and by the print statement to compute the “informal” string representation of an object: • https://gist.github.com/1397677
Animal class classAnimal: def__init__(self, name, noise): self.name = name self.noise = noise
Farm class classFarm: def__init__(self): self.animals = [] defadd(self, animal): self.animals.append(animal)
Farm class def__str__(self): s = “” for animal inself.animals: s += 'Old MacDonald had a farm, EE-I-EE-I-O,\n' s += 'And on that farm he had a '+animal.name+', EE-I-EE-I-O,\n' s += 'With a '+ animal.noise + animal.noise+' here and a ‘ s +=animal.noise + animal.noise +' there\n' s += 'Here a '+ animal.noise +', there a ‘ s += animal.noise + ', everywhere a ‘ + animal.noise s += animal.noise + '\n' s += 'Old MacDonald had a farm, EE-I-EE-I-O.\n‘ returns
Sing the song! >>> farm = Farm() >>> farm.add(Animal('cow','moo')) >>> print farm Old MacDonald had a farm, EE-I-EE-I-O, And on that farm he had a cow, EE-I-EE-I-O, With a moomoo here and a moomoo there Here a moo, there a moo, everywhere a moomoo Old MacDonald had a farm, EE-I-EE-I-O. >>> farm.add(Animal('duck','kwak')) >>> farm.add(Animal('dog','woof')) >>> farm.add(Animal('cat','miaoo'))
Sing the song! >>> print farm Old MacDonald had a farm, EE-I-EE-I-O, And on that farm he had a cow, EE-I-EE-I-O, With a moomoo here and a moomoo there Here a moo, there a moo, everywhere a moomoo Old MacDonald had a farm, EE-I-EE-I-O, And on that farm he had a duck, EE-I-EE-I-O, With a kwakkwak here and a kwakkwak there Here a kwak, there a kwak, everywhere a kwakkwak Old MacDonald had a farm, EE-I-EE-I-O, And on that farm he had a dog, EE-I-EE-I-O, With a woofwoof here and a woofwoof there Here a woof, there a woof, everywhere a woofwoof Old MacDonald had a farm, EE-I-EE-I-O, And on that farm he had a cat, EE-I-EE-I-O, With a miaoomiaoo here and a miaoomiaoo there Here a miaoo, there a miaoo, everywhere a miaoomiaoo Old MacDonald had a farm, EE-I-EE-I-O.
A Time class • We’ll define a class called Time that records the time of day (The “Think Python” Book, ch. 16 & 17): classTime(object): """represents the time of day. attributes: hour, minute, second""“ def__init__(self, hour, minute, second): self.hour = hour self.minute = minute self.second = second >>> time = Time(11, 9, 30)
Time class – cont. >>> time = Time(11, 59, 30) • How would we print a Time instance? def__str__(self): return"%.2d:%.2d:%.2d" % (self.hour, self.minute, self.second) >>> print time 11:59:30 >>> time.hour = 0 >>> print time 00:59:30 String formatting: http://docs.python.org/release/2.5.2/lib/typesseq-strings.html
Time class – cont. • We want to add times – for example, it’s 16:00:00 and I have a meeting in 2 hours: 16:00:00 + 02:00:00 = 18:00:00 def__add__(self, other): hour = self.hour+other.hour minute = self.minute+other.minute second = self.second+other.second return Time(hour, minute, second) • Is this right? What will happen when adding 16:00:00 to 16:00:00?
Adding times – cont. • 0≤hour<24, 0≤minute<60, 0≤second<60 • 100 minutes = 1 hour 40 minutes def__add__(self, other): hour = self.hour + other.hour minute = self.minute + other.minute second = self.second + other.second minute += second / 60 second = second % 60 hour += minute / 60 minute = minute % 60 hour = hour % 24 returnTime(hour, minute, second)
Adding times – cont. >>> t1 = Time(16,0,0) >>> t2 = Time(2,0,0) >>> print t1+t2 18:00:00 >>> printt1+t1 08:00:00
Subtracting times • Just like addition: def__sub__(self, other): hour = self.hour - other.hour minute = self.minute - other.minute second = self.second - other.second minute += second / 60 second = second % 60 hour += minute/60 minute = minute % 60 hour = hour % 24 return Time(hour, minute, second)
Even better def__init__(self, hour, minute, second): minute = minute + second / 60 hour = hour + minute / 60 self.hour= hour % 24 self.minute= minute % 60 self.second= second % 60 def__add__(self, other): hour = this.hour + other.hour minute = this.minute + other.minute second = this.second + other.second returnTime(hour, minute, second)
Debugging • We want to write a method that verifies that a Time instance is valid: defvalid(self): ifself.hour< 0 orself.minute< 0 orself.second< 0: returnFalse ifself.hour>=24 orself.minute>= 60 orself.second>= 60: returnFalse returnTrue
Exceptions • When the program reaches a state it can’t handle or an error it cannot recover from, it raises an exception. • This means it sends an error to the user • There are different types of errors. Examples: • IndexError • ZeroDivisionError • ValueError • TypeError • … Full list: http://docs.python.org/library/exceptions.html
Debugging – cont. • We want to verify that a time is valid before using it and raise an exception if a time is invalid: def__add__(self,other): ifnotself.valid() ornotother.valid(): raiseValueError(‘invalid Time object in addition’) …. • This will help us find errors and alert users of the code on wrong usage • Optional: This can also be written using assert: def__add__(self,other): assert self.valid() andother.valid() ….
Comparing Time instances • We’d like to be able to compare times. Right now: >>> t1 = Time(16,0,0) >>> t2 = Time(5,0,0) >>> t1>t2 False >>> t1 = Time(16,0,0) >>> t1>t2 True • This happens because python compares the addresses!
Comparing Time instances – cont. • We’d like to be able to compare times: def __cmp__(self, other): tup1 = (self.hour, self.minute, self.second) tup2 = (other.hour, other.minute, other.second) returncmp(tup1, tup2) >>> Time(16,0,0)>Time(11,30,0) True >>> Time(16,0,0)>Time(16,0,1) False
Object representation >>> t1 = Time(16,0,0) >>> print t1 # calls __str__ 16:00:00 >>> t1 <__main__.Time object at 0x01FEBA70> • If we want a different output we must override the __repr__ method
Object representation – cont. def__repr__(self): returnself.__class__.__name__+" instance: "+self.__str__() >>> t = Time(16,0,0) >>> t Time instance: 16:00:00 • Note the use of these attributes: >>> cls = t.__class__ >>> cls <class '__main__.Time'> >>> cls.__name__ Time
Time as number of seconds • We note that the time of day can also be denoted by the number of seconds since the beginning of the day: defto_seconds(self): returnself.hour*3600 + self.minute*60 + self.second >>> time = Time(16,0,0) >>> time.to_seconds() 5760 • We already have the other direction from __init__ (see here)
Time as number of seconds – cont. • This also simplifies the _add__ and __sub__ methods: def__add__(self, other): secs = self.to_seconds() + other.to_seconds() returnTime(0,0, secs) def__sub__(self,other): secs= self.to_seconds() - other.to_seconds() returnTime(0,0, secs)
Comparing is also easier • We can also change __cmp__: def__cmp__(self, other): returncmp(self.to_seconds(), other.to_seconds()) >>> t1 = Time(16,0,0) >>> t2 = Time(21,0,0) >>> t1>t2 False
Type checking, adding integers • The next step is to allow __add__ to add either seconds or Time def__add__(self, other): secs= self.to_seconds() ifisinstance(other, Time): # is other a Time? secs += other.to_seconds() elifisinstance(other, int): # is other an int? secs += other return Time(0,0,secs) # creating a new time
Type checking, adding integers • Now we can use the + operator with either int or Time: >>> time = Time(16,0,0) >>> print time+60 16:01:00 >>> printtime+Time(0,1,0) 16:01:00
Type checking, adding integers • What if we add a float? • Let’s change the if-else: def__add__(self, other): secs = self.to_seconds() ifisinstance(other,Time): secs+= other.to_seconds() elifisinstance(other,int): secs+= other else: raiseTypeError("Can't add Time and “ +other.__class__.__name__) returnTime(0,0,secs)
Type checking, adding integers >>> time + 5.0 Traceback (most recent call last): File "<pyshell#167>", line 1, in <module> t1+5. File "C:/python_course/Time.py", line 38, in __add__ raise TypeError("Can't add Time and "+other.__class__.__name__) TypeError: Can't add Time and float
Right-side addition >>> print time + 60 16:01:00 >>> print 60 + time Traceback (most recent call last): File "<pyshell#173>", line 1, in <module> 60 + time TypeError: unsupported operand type(s) for +: 'int' and 'Time‘ • We need to implement __radd__!
Right-side addition – cont. def__radd__(self,other): returnself.__add__(other) >>> print 60 + time 16:01:00 • Alternatively we can write: def__radd__(self,other): returnself+other
The benefits of overriding + • We can use the built-in sum: >>> sum([Time(1,0,1),Time(2,0,2), Time(3,0,3)]) Time instance: 06:00:06
Home work 6: Point class • We will write a class for a Point - 2-D vector • Operator overloading: http://docs.python.org/library/operator.html • All instructions in hw6.pdf • Use what we learned: • class Rational • class Time