Introduction Programming Using Python Lecture 8 Dr. Zhang COSC 1437 Fall 2017 Nov 30, 2017
Chapter 12 Inheritance and Class Design Review Suppose you will define classes to model circles, rectangles, and triangles. These classes have many common features. What is the best way to design these classes so to avoid redundancy? The answer is to use inheritance.
Objectives To develop a subclass from a superclass through inheritance ( 12.2). To override methods in the subclass ( 12.3). To explore the object class and its methods ( 12.4). To understand polymorphism and dynamic binding ( 12.5). To determine if an object is an instance of a class using the isinstance function ( 12.6). To discover relationships among classes ( 12.8). To design classes using composition and inheritance relationships ( 12.9-12.11).
Superclasses and Subclasses -color: str -filled: bool GeometricObject GeometricObject(color: str, filled: bool) getcolor(): str setcolor(color: str): None isfilled(): bool setfilled(filled: bool): None str (): str The color of the object (default: white). Indicates whether the object is filled with a color (default: false). Creates a GeometricObject with the specified color and filled values. Returns the color. Sets a new color. Returns the filled property. Sets a new filled property. Returns a string representation of this object. -radius: float Circle Circle(radius: float, color: str, filled: bool) getradius(): float setradius(radius: double): None getarea(): float getperimeter(): float getdiameter(): float printcircle(): None -width: double -height: double Rectangle Rectangle(width: float, height: float color: string, filled: bool) getwidth(): float setwidth(width: float): None getheight(): float setheight(height: float): None getarea(): float getperimeter(): float Sample code: GeometricObject.py,Circle.py,Rectangle.py TestCircleRectangle.py
Overriding Methods A subclass inherits methods from a superclass. Sometimes it is necessary for the subclass to modify the implementation of a method defined in the superclass. This is referred to as method overriding.
The object Class Every class in Python is descended from the object class. If no inheritance is specified when a class is defined, the superclass of the class is object by default. There are more than a dozen methods defined in the object class. We discuss four methods new (), init (), str (), and eq (other) here. class ClassName:... Equivalent class ClassName(object):...
The new, init Methods All methods defined in the object class are special methods with two leading underscores and two trailing underscores. The new () method is automatically invoked when an object is constructed. This method then invokes the init () method to initialize the object. Normally you should only override the init () method to initialize the data fields defined in the new class.
The str Method The str () method returns a string representation for the object. By default, it returns a string consisting of a class name of which the object is an instance and the object s memory address in hexadecimal.
The eq Method The eq (other) method returns True if two objects are the same. By default, x. eq (y) (i.e., x == y) returns False, but x. eq (x) is True. You can override this method to return True if two objects have the same contents.
Polymorphism The three pillars of object-oriented programming are encapsulation, inheritance, and polymorphism. The inheritance relationship enables a subclass to inherit features from its superclass with additional new features. A subclass is a specialization of its superclass; every instance of a subclass is also an instance of its superclass, but not vice versa. For example, every circle is a geometric object, but not every geometric object is a circle. Therefore, you can always pass an instance of a subclass to a parameter of its superclass type. Example code: PolymorphismDemo.py
Dynamic Binding Dynamic binding works as follows: Suppose an object o is an instance of classes C1, C2,..., Cn-1, and Cn, where C1 is a subclass of C2, C2 is a subclass of C3,..., and Cn-1 is a subclass of Cn. That is, Cn is the most general class, and C1 is the most specific class. In Python, Cn is the object class. If o invokes a method p, the JVM searches the implementation for the method p in C1, C2,..., Cn-1 and Cn, in this order, until it is found. Once an implementation is found, the search stops and the first-found implementation is invoked. C n C n-1..... C 2 C 1 object Since o is an instance of C 1, o is also an instance of C 2, C 3,, C n-1, and C n
The isinstance Function The isinstance function can be used to determine if an object is an instance of a class.
Case Study: A Reusable Clock tkinter.canvas StillClock The get and set methods for these data fields are provided in the class, but omitted in the UML diagram for brevity. -hour: int -minute: int -second: int The hour in the clock. The minute in the clock. The second in the clock. StillClock(container) setcurrenttime(): None Constructs a default clock for the current time, placed inside a container. Sets hour, minute, and second to current time.
Relationships among Classes Association Aggregation Composition Inheritance
Association Association represents a general binary relationship that describes an activity between two classes. An association is usually represented as a data field in the class. Take 5..60 Student * Course Teach 0..3 1 Teacher Faculty class Student: def addcourse(self, course): # add course to a list class Course: def addstudent(self, student): # add student to a list class Faculty: def addcourse(self, course): # add course to a list def setfaculty(self, faculty): # Code omitted
Association Between Same Class Association may exist between objects of the same class. For example, a person may have a supervisor. Person 1 1 Supervisor
Aggregation and Composition Aggregation is a special form of association, which represents an ownership relationship between two classes. Aggregation models the has-a relationship. If an object is exclusively owned by an aggregated object, the relationship between the object and its aggregated object is referred to as composition. Composition Aggregation Name Person Address
Representing Aggregation in Classes An aggregation relationship is usually represented as a data field in the aggregated class. class Name:... class Student: def _init_(self, name, address) self.name = name self.address = address class Address:...... Aggregated class Aggregating class Aggregated class
Chapter 13 Files and Exception Handling How do you write data to a file and read the data back from a file? You need to create a file object that is associated with a physical file. This is called opening a file. The syntax for opening a file is as follows: file = open(filename, mode) 'r' 'w' 'a' 'rb' 'wb' Open a file for reading only. Open a file for writing only. Open a file for appending data. Data are written to the end of the file. Open a file for reading binary data. Open a file for writing binary data.
Write to a File Code Example: writedemo.py file read([number: int]): str readline(): str readlines(): list write(s: str): None close(): None Returns the specified number of characters from the file. If the argument is omitted, the entire remaining contents are read. Returns the next line of file as a string. Returns a list of the remaining lines in the file. Writes the string to the file. Closes the file.
Testing File Existence
Read from a File After a file is opened for reading data, you can use the read method to read a specified number of characters or all characters, the readline() method to read the next line, and the readlines() method to read all lines into a list. Code example: readdemo.py
Append Data to a File You can use the 'a' mode to open a file for appending data to an existing file. def main(): # Open file for appending data outfile = open("info.txt", "a") outfile.write("\npython is interpreted\n") outfile.close() # Close the input file main() # Call the main function
Writing/Reading Numeric Data To write numbers, convert them into strings, and then use the write method to write them to a file. In order to read the numbers back correctly, you should separate the numbers with a whitespace character such as ' ', '\n. Code example: WriteReadNumbers.py
from random import randint WriteReadNumbers.py def main(): # Open file for writing data outfile = open("numbers.txt", "w") for i in range(10): outfile.write(str(randint(0, 9)) + " ") outfile.close() # Close the file # Open file for reading data infile = open("numbers.txt", "r") s = infile.read() numbers = [eval(x) for x in s.split()] for number in numbers: print(number, end = " ") infile.close() # Close the file main() # Call the main function
File Dialogs from tkinter.filedialog import askopenfilename from tkinter.filedialog import asksaveasfilename filenameforreading = askopenfilename() print("you can read from from " + filenameforreading) filenameforwriting = asksaveasfilename() print("you can write data to " + filenameforwriting)
File Dialogs
File Editor FileEditor.py
Problem: Counting Each Letter in a File The problem is to write a program that prompts the user to enter a file and counts the number of occurrences of each letter in the file regardless of case. Code Example: CountEachLetter.py
Retrieving Data from the Web Using Python, you can write simple code to read data from a Website. All you need to do is to open a URL link using the urlopen function as follows: infile = urllib.request.urlopen('http://www.yahoo.com') import urllib.request infile = urllib.request.urlopen('http://www.yahoo.com/index.htm l') print(infile.read().decode())
Retrieving Data from the Web import urllib.request def main(): url = input("enter an URL for a file: ").strip() infile = urllib.request.urlopen(url) s = infile.read().decode() # Read the content as string counts = countletters(s.lower()) # Display results for i in range(len(counts)): if counts[i]!= 0: print(chr(ord('a') + i) + " appears " + str(counts[i]) + (" time" if counts[i] == 1 else " times")) # Count each letter in the string def countletters(s): counts = 26 * [0] # Create and initialize counts for ch in s: if ch.isalpha(): counts[ord(ch) - ord('a')] += 1 return counts main() # Call the main function
Exception Handling When you run the program in Listing 11.3 or Listing 11.4, what happens if the user enters a file or an URL that does not exist? The program would be aborted and raises an error. For example, if you run Listing 11.3 with an incorrect input, the program reports an IO error as shown below:
The try... except Clause
The try... except Clause
The try... except Clause from random import randint def main(): # Open file for writing data outfile = open("numbers.txt", "w") for i in range(10): outfile.write(str(randint(0, 9)) + " ") outfile.close() # Close the file # Open file for reading data infile = open("numbers.txt", "r") s = infile.read() numbers = [eval(x) for x in s.split()] for number in numbers: print(number, end = " ") infile.close() # Close the file main() # Call the main function
Raising Exceptions You learned how to write the code to handle exceptions in the preceding section. Where does an exception come from? How is an exception created? Exceptions are objects and objects are created from classes. An exception is raised from a function. When a function detects an error, it can create an object of an appropriate exception class and raise the object, using the following syntax: raise ExceptionClass("Something is wrong") Code Example: RaiseException.py
Processing Exceptions Using Exception Objects You can access the exception object in the except clause. Code example: ProcessingExceptionObject.py
Binary IO Using Pickling To perform binary IO using pickling, open a file using the mode 'rb' or 'wb' for reading binary or writing binary and invoke pickle module s dump and load functions to write and read data. Code example: BinaryIODemo.py
BinaryIODemo.py import pickle def main(): # Open file for writing binary outfile = open("pickle.dat", "wb") pickle.dump(45, outfile) pickle.dump(56.6, outfile) pickle.dump("programming is fun", outfile) pickle.dump([1, 2, 3, 4], outfile) outfile.close() # Close the output file # Open file for reading binary infile = open("pickle.dat", "rb") print(pickle.load(infile)) print(pickle.load(infile)) print(pickle.load(infile)) print(pickle.load(infile)) infile.close() # Close the input file main() # Call the main function
Detecting End of File If you don t know how many objects are in the file, how do you read all the objects? You can repeatedly read an object using the load function until it throws an EOFError exception. When this exception is raised, catch it and process it to end the file reading process. Code Example: DetectEndOfFile.py
Case Study: Address Book Now let us use object IO to create a useful project for storing and viewing an address book. The user interface of the program is shown below. The Add button stores a new address at the end of the file. The First, Next, Previous, and Last buttons retrieve the first, next, previous, and last addresses from the file, respectively.
Chapter 15 Recursion Suppose you want to find all the files under a directory that contains a particular word. How do you solve this problem? There are several ways to solve this problem. An intuitive solution is to use recursion by searching the files in the subdirectories recursively.
Computing Factorial factorial(0) = 1; factorial(n) = n*factorial(n-1); n! = n * (n-1)! Code example: ComputeFactorial.py
ComputeFactorial.py def main(): n = eval(input("enter a nonnegative integer: ")) print("factorial of", n, "is", factorial(n)) # Return the factorial for a specified number def factorial(n): if n == 0: # Base case return 1 else: return n * factorial(n - 1) # Recursive call main() # Call the main function
Computing Factorial factorial(3) = 3 * factorial(2) = 3 * (2 * factorial(1)) = 3 * ( 2 * (1 * factorial(0))) = 3 * ( 2 * ( 1 * 1))) = 3 * ( 2 * 1)
Computing Factorial factorial(4) = 4 * factorial(3) = 4 * 3 * factorial(2) = 4 * 3 * (2 * factorial(1)) = 4 * 3 * ( 2 * (1 * factorial(0))) = 4 * 3 * ( 2 * ( 1 * 1))) = 4 * 3 * ( 2 * 1) = 4 * 3 * 2 = 4 * 6 = 24
Characteristics of Recursion All recursive methods have the following characteristics: One or more base cases (the simplest case) are used to stop recursion. Every recursive call reduces the original problem, bringing it increasingly closer to a base case until it becomes that case. In general, to solve a problem using recursion, you break it into subproblems. If a subproblem resembles the original problem, you can apply the same approach to solve the subproblem recursively. This subproblem is almost the same as the original problem in nature with a smaller size.
Problem Solving Using Recursion Let us consider a simple problem of printing a message for n times. You can break the problem into two subproblems: one is to print the message one time and the other is to print the message for n-1 times. The second problem is the same as the original problem with a smaller size. The base case for the problem is n==0. You can solve this problem using recursion as follows:
Recursion vs. Iteration Recursion is an alternative form of program control. It is essentially repetition without a loop. Recursion bears substantial overhead. Each time the program calls a method, the system must assign space for all of the method s local variables and parameters. This can consume considerable memory and requires extra time to manage the additional space.
Advantages of Using Recursion Recursion is good for solving the problems that are inherently recursive.
Lab Lab: Digital book 471 13.2 No assignment Do class project