More Control and Expanded I/O options Part 1: Defining classes • By the end of this session, you should be able to define a class, store it in a file, import it and use it in another program. – self as a parameter – local variables – parameters and arguments – special operators – polymorphism Recall from first week • A class is a definition of a category of objects and the methods that operate on those objects – A specific instance of a class is called an object • A class may be related to other classes, and inherit properties from the other class or extend the properties of another class. – A class student is a subclass of person • A student has all the characteristics of a person, but has other characteristics as well (perhaps major, gpa, etc.) Backward references • We will use examples that were introduced earlier. Look back at the previous slides and look at the book to find the details that were provided then. • Examples: – greatest common divisor – television class Defining a class • Similar to defining a function, which we have done. – We saw earlier that a class consists of attributes for the data and methods for operating on the data. – These get translated into Python code as • references to self • functions defined on self, other parameters • class introduces a class definition – classes can reference each other Point Class This is what allows us to instantiate an instance of the class – an object. • class Point: • __init__ called the constructor. Executed when a new object is created from a class. • self lets Python know that a method or data is a member of the class. – For a data member it should be self._x where _x is the class data attribute. Without the self a variable is only a local variable inside a class method. – For a method the self is the first parameter in the parameter list. __init__(self, . . .) 6 Indentation Pattern for a Class So, this one class includes three methods (function definitions) Notice the indentation: Each function definition is indented and the body of each function is indented within the function. 7 Creating an instance (an object) from a class class Point: def __init__(self): self._x = 0 self._y = 0 • __init__(self) defines the structure of the objects of this class. There are two components to objects of this class: _x and _y (yes, the _ is a significant part of the name.) • When a program uses the Point class, the __init__ function establishes its parts and assigns each of the parts the value 0 in this example. • Creating a Point object: a = Point() a is now a Point object. It consists of two numbers, which we might think of as the x and y components of the Point The setX, setY methods def setX(self, val): self._x = val def setY(self, val): self._y = val _x and _y make these parameters invisible to the caller. • We can set the value of the Point a: a = Point() a.setX(5) a.setY(2) a is now the point <5,2> (using < > to avoid confusion with () and [] which already have meaning.) Referencing the components of the Point • Since _x and _y are hidden, the program cannot reference – a.x or a.y • Instead, – a.getX() – a.getY() Next example uses corner instead of a as the name of the Point. Connection Between a Method (setX) for the object corner and setX definition in the class. 11 Two Perspectives • Left part of each box: perspective from outside the Point class. • Right part of each box: perspective from inside the Point class. Argument used to reference the object’s methods from the program Parameter used to define the object 12 Accessors and Mutators • Accessors and mutators let users of the class access data members and change data member values. • getX(self) can return the X data member. – This is an accessor • setX(self, val) will change the X data member to be val. – This is a mutator 13 Summary: Creating a point class class Point: def __init__(self): self._x = 0 self._y = 0 def getX(self, val): return self._x def getY(self, val): return self._y Point has two components, x and y, initially set to 0 Point has methods that allows its x and y components to be referenced 14 Point Class (Continued) def setX(self, val): self._x = val def setY(self.val): self._y = val Point has methods that allow its x and y components to be modified. 15 Using the Point Class #create a new object corner of type Point from SimplePoint import Point corner = Point() corner.setX(8) #8 is value of _x in object corner corner.setY(6) #6 is value of _y in object corner This assumes that we have created a file with the SimplePoint class definition. 16 #Example SimplePoint code from Chapter 6 of text class Point: def __init__(self): This code stored in file named self._x = 0 SimplePoint.py self._y = 0 def __str__(self): return '<'+str(self._x)+','+str(self._y)+'>’ def getX(self): return self._x def setX(self, val): self._x = val def getY(self): return self._y def setY(self, val): from SimplePoint import Point self._y = val a=Point() a.setX(5) a.setY(2) b = Point() b.setX(-8) This code stored in file named b.setY(-3) class-import-test.py print "a is ", a, " b is ",b #Example SimplePoint code from Chapter 6 of text class Point: Class name match def __init__(self): self._x = 0 self._y = 0 def __str__(self): return '<'+str(self._x)+','+str(self._y)+'>’ def getX(self): This code stored in file named return self._x SimplePoint.py def setX(self, val): self._x = val File name match def getY(self): return self._y def setY(self, val): from SimplePoint import Point self._y = val a=Point() a.setX(5) a.setY(2) b = Point() b.setX(-8) This code stored in file named b.setY(-3) class-import-test.py print "a is ", a, " b is ",b class Echo: def __init__(self, anyStr): self.text = anyStr def __str__(self): return str(self.text) + " " + str(self.text) Check Point • Create a class – Make a class called Echo – It has one parameter, a string – It uses __init__ to instantiate an object and __str__ to cast the object as a string for printing and return the string duplicated, with a space between the copies. • Create a calling program to obtain a string from the user and call Echo to print it out twice Here is a sample run vu50390:ch06 lcassel$ vu50390:ch06 lcassel$ python useecho.py Enter your string Greetings!! Greetings!! Greetings!! vu50390:ch06 lcassel$ Improved Point class #if no values are specified for x and y then #the values are set to 0. def __init__(self, initX = 0, initY = 0) self._x = initX self._y = initY #Scales the point by a value factor. def scale(self, factor): self._x *= factor self._y *= factor 21 Improved Point Class (continued) def distance(self, other): dx = self._x - other._x dy = self._y – other._y return sqrt(dx*dx + dy*dy) Note – this requires import math or from math import sqrt #using the distance method point1 = Point(5,20) point2 = Point(45,60) apartAmt = point1.distance(point2) 22 Improved Point Class (continued) #normalize point – make its distance to the #origin 1 def normalize(self): mag = self.distance(Point()) #Point() creates new point at origin if mag > 0: #don't scale if point is at origin self.scale(1/mag) 23 Improved Point Class (continued) #allow print to be able to print a point object. def __str__(self): return '<'+str(self._x)+', '+str(self._y)+ '>' #using __str__ method new = Point(3, 5) print new #output <3, 5> 24 Improved Point Class (continued) • Can not use <3,5> to initialize an object. point = <3,5> #this is an error • Can overload most operators so that they have a new meaning when used with new objects. • An example is + operator when used with int and float does addition. When used with str it does concatenation (sticks the two strings together). 25 Improved Point Class (continued) #overloading operators: + overloading def __add__(other): return Point(self._x +other._x, self._y+other._y #using the __add__ method new = Point(3, 5) old = Point(4, 7) total = new + old print total #output <7, 12> 26 Polymorphism • Operator may do a different operation depending on the type that is passed into the operator. • Multiplication operator: int or float multiply each component by the value, point do a dot product. • isinstance(variable, Type) returns True if variable is of type Type. 27 Polymorphism #if val is an int or float it does the # if code #if a Point it does the elif code. def __mul__(self, val): if isinstance(val, (int, float)): #performs regular multiplication #operation. return Point(self._x*val, self._y*val) elif isinstance(val, Point): #performs dot product operation. return self._x*val._x + self._y*val._y 28 Spot Check • Do exercise 6.4 in the text. – Enter the code shown. – Execute each of the examples – Explain the results Other examples • Look at the descriptions of the Television and Fraction classes in the text for further examples of class definition. More control – Catching exceptions Exceptions: How to Deal with Error Situations number = 0 while not 1 <= number <= 10: try: number= int(raw_input('Enter number from 1 to 10: ')) if not 1 <= number <= 10: print 'Your number must be from 1 to 10:' except ValueError: print 'That is not a valid integer.' Here: recognize an error condition and deal with it book slide If the named error occurs, the “except” clause is executed and the loop is terminated. 32 Exceptions (continued) • What if a negative is entered for square root? • Can raise an exception when something unusual occurs. def sqrE(number): if number < 0: raise ValueError('number must be positive') #do square root code as before Note: ValueError is an existing, defined error class book slide 33 Exceptions (continued) #What if value entered is not a number? def sqrtF(number): if not isinstance(number, (int, float)): raise TypeError('number must be numeric') if number < 0: raise ValueError('number must be positive') #do square root code as before book slide 34 How Much Type Checking is Enough? • A function with little type checking of its parameters may be difficult to diagnose errors. • A function with much type checking of its parameters will be harder to write and consume more time executing. • If the function is one that only you will use you may need less type checking. • A function written for others should have more type checking. book slide 35 Spot check on Exceptions • In pairs, write python code to do the following: – Accept input from the keyboard • Prompt with instructions to enter a number, and to enter some character you choose to end – Verify that the value read is numeric – Calculate the minimum, maximum and average of the values read – Terminate reading when a non numeric character is entered – Print out the values calculated 36 Formatting and File access Building on basics • We had – Input from the keyboard • nameIn = raw_input(“What is your name?”) – and output to the console • print “Hello”, nameIn • Additions: – default for value not input: • nameIn = raw_input(“What is your name?”) • if not nameIn: No input provided nameIn = “Anonymous” More additions • Printing a simple list of strings includes a space between each pair. >>> team = "Wildcats" >>> rank = 5 >>> print team, ": ranked", rank, "this week." Wildcats : ranked 5 this week. >>> – Unwanted space between team name and : – to fix this use concatenation of strings (+ operator). Must explicitly convert numbers to strings. Gain full control of the spacing >>> print team+": ranked " + str(rank) +" this week." Wildcats: ranked 5 this week. Formatting Strings • Further control of how individual fields of output will be presented. – % is used to indicate a formatting code and also a tuple of items to be formatted – %s for strings – %d for integers (d for digits?) – %f for floats (numbers with decimal parts) • %.3f displays three decimal places Formatted Strings (continued) • Can write previous statement using formatting strings like this. Notice quotes >>> print '%s: ranked %d this week.'%(team, rank) around the whole Wildcats: ranked 5 this week. specification of the formatting. • Format strings are: – %s is for strings – %d is for integers – %f is for floats. %.2f gives two decimal places. 41 Formatting details • Further options – %10s -- string with 10 spaces, minimum – %4d -- number with 4 spaces, minimum – -%5.2f -- float with 5 places, of which two are decimal positions Note: %n.df makes the >>> print 'Rank %5.2f as a float.'%rank Rank 5.00 as a float. >>> print 'Rank %10.2f as a float.'%rank Rank 5.00 as a float. total columns for the number =n, of which d are for the decimal places >>> rank = 100 >>> print "Rank %3.2f with field too small"%rank Rank 100.00 with field too small %3.2f means total 3 spaces, one is for the decimal point and two for the decimal digits, none for the whole number. Automatically expanded to fit the actual value. Short spot check • Write code to print out – Today is 10 October 2012 – Where the date consists of 3 variables • Day is an integer • Month is a string • Year is an integer – Use the formatting tools we just saw and make the day number always 2 digits, the month name a set length (long enough for any month) and the year four digits. Working with Files • Information stored in RAM (main memory) goes away (is volatile) when the computer is shut off. • Information stored on disk is nonvolatile (does not go away when the computer is turned off). • Writing to and reading from a file can help preserve information between different executions of a program. 44 Python File Type • creating a new file instance is accomplished in the same way that a new list object is made. fileObj = file(filename) 45 File Operations Syntax Semantics close() disconnect file from Python file variable and save file. flushes buffer of written characters. flush() read() returns a string with remaining contents of the file. read(size) returns a string with size bytes remaining in file. readline() returns string that contains next line in the file. 46 File Operations (continued) Syntax Semantics readlines() returns a list of strings of the remaining lines in the file. write(s) writes s to the file. No newlines are added. writes the lines in seq to the file. writelines(seq) for line in f: iterates through the line f, one line at a time. 47 Reading from a File: Counting lines, words, and characters version 1 – corrected typos and added formatting filename = raw_input('What is the filename? ') source = file(filename) text = source.read() # Read entire file as one string numchars = len(text) Note – this version reads the whole numwords = len(text.split()) file at once, as a single string numlines = len(text.split('\n')) print '%10d Lines\n%10d Words\n%10d Characters'%(numlines,numwords,numchars) source.close() What is the filename? citeseertermcount.txt 30002 Lines 156521 Words 920255 Characters 48 Reading from a File: Counting lines, words, and characters version 2 numlines=numwords=numchars=0 line=source.readline() while line: # line length is not zero numchars+=len(line) numwords +=len(line.split()) numlines+=1 # Done with current line. Read the next line=source.readline() Now, we read one line at a time, process it, and read the next. print '%10d Lines\n%10d Words\n%10d Characters'%(numlines,numwords,numchars) source.close() What is the filename? citeseertermcount.txt 30001 Lines 156521 Words Note different number of lines 920255 Characters 49 Reading from a File: Counting lines, words, and characters version 3 filename = raw_input('What is the filename? ') source = file(filename) numlines = numwords = numchars = 0 for line in source: #reads one line at a time until no more. numchars += len(line) Note that “for line in source” actually numwords += len(line.split()) does the read of a line. No explicit numlines += 1 readline is used. print '%10d Lines\n%10d Words\n%10d Characters'%(numlines,numwords,numchars) source.close() 30001 Lines 156521 Words 920255 Characters Note the number of lines 50 Spot check • Read a file of your choice – anything you have is fine • Find the longest line – Output the line number and its length in characters Writing to a File • Creating a new file object that can be written to in Python with a file name of filename. result = file(filename, 'w') • If the file with filename already exists then it will be overwritten. • Only strings can be written to a file pi = 3.14159 result.write(pi) result.write(str(pi)) #this is illegal #this is legal 52 Writing to a File • When is the information actually written to a file? • File writing is time expensive so files may not be written immediately. • A file can be forced to be written in two ways: – flush(): file written but not closed. – close(): file written and then closed. 53 File Write Danger • Note that there is no built-in protection against destroying a file that already exists! • If you want to safeguard against accidentally overwriting an existing file, what would you do? – Discuss Trying to Read a File That Doesn't Exist. • What if opening file for reading and no file with that name exists? IOError – crashes program. To avoid this use an exception. filename = raw_input('Enter filename: ') try: source = file(filename) except IOError: print 'Sorry, unable to open file', \ filename 55 File Utilities # Prompt for filename until file is successfully opened. def fileReadRobust(): source = None while not source: filename = raw_input('Input filename: ') try: source = file(filename) except IOError: print 'Sorry, unable to open file', filename return source 56 File Utilities (continued) def openFileWriteRobust(defaultName): """Repeatedly prompt user for filename until successfully opening with write access. Return a newly open file object with write access. defaultName a suggested filename. This will be offered within the prompt and used when the return key is pressed without specifying another name. """ writable = None while not writable: # still no successfully opened file prompt = 'What should the output be named [%s]? '% defaultName filename = raw_input(prompt) if not filename: # user gave blank response filename = defaultName # try the suggested default try: writable = file(filename, 'w') except IOError: print 'Sorry. Unable to write to file', filename return writable 57 Spot check • Enter the code shown for the robust file open. Add a call to this function. • How can you test this code? Testing the File Utilities from FileUtilities import * sourceFile=openFileReadRobust() if sourceFile <> None: print "Successful read of ",sourceFile filenone="anyname" outFile=openFileWriteRobust(filenone) if outFile <> None: print "File ", outFile, " opened for writing" What is the filename? citeseertermcount.txt Successful read of <open file 'citeseertermcount.txt', mode 'r' at 0x60f9d0> What should the output be named [anyname]? abc.txt File <open file 'abc.txt', mode 'w' at 0x60fa20> opened for writing Numbering lines in a file # Program: annotate.py # Authors: Michael H. Goldwasser # David Letscher # # This example is discussed in Chapter 8 of the book # Object-Oriented Programming in Python # from FileUtilities import openFileReadRobust, openFileWriteRobust print 'This program annotates a file, by adding' print 'Line numbers to the left of each line.\n' source = openFileReadRobust() annotated = openFileWriteRobust('annotated.txt') # process the file linenum = 1 for line in source: annotated.write('%4d %s' % (linenum, line) ) linenum += 1 source.close() annotated.close() print 'The annotation is complete.' Running the annotation program This program annotates a file, by adding Line numbers to the left of each line. What is the filename? fileUtilities.py What should the output be named [annotated.txt]? annotatedUtilities.txt The annotation is complete. Directory after the program runs: FileUtilities.pyc abc.txt annotate.py annotatedUtilities.txt citeseertermcount.txt readfile1.py fileUtilTest.py readfile2.py fileUtilities.py readfile3.py readexception.py 61 The annotated file 1 # Program: FileUtilities.py 2 # Authors: Michael H. Goldwasser 3 # David Letscher 4 # 5 # This example is discussed in Chapter 8 of the book 6 # Object-Oriented Programming in Python 7 # 8 """A few utility functions for opening files.""" 9 def openFileReadRobust(): 10 """Repeatedly prompt user for filename until successfully opening with read access. 11 12 Return the newly open file object. 13 """ 14 source = None 15 while not source: # still no successfully opened file 16 filename = raw_input('What is the filename? ') 17 try: 18 source = file(filename) 19 except IOError: 20 print 'Sorry. Unable to open file', filename 21 return source 22 23 def openFileWriteRobust(defaultName): 24 """Repeatedly prompt user for filename until successfully opening with write access. 25 26 Return a newly open file object with write access. Rest not shown for space limitations Spot Check 2 • Run the annotate program against a file of your choosing and get the line numbers added. – Be careful not to overwrite the original file. – Modify the code to remove the file numbers from the file Tally • Read through the case study of constructing a tally sheet class. • Compare what you see here to the frequency distribution content that you saw in the NLTK book. NLTK chapter 3 • That is written very much as a tutorial and I don’t think I can do much with slides and no narration. • Please read through that chapter and do the “Your turn” exercises. Use the Discussion board to comment on what you do and to share observations and ask questions. Assignment • In Two weeks: – Do either exercise 8.18 or exercise 8.21 – (Do you prefer to work with numbers or words?) – Be sure to design good test cases for your program. • For chapter review (and quiz preparation) be sure you can do exercises 8.7 – 8.9