Solutions Manual For Python Program
Posted By admin On 24.01.20This section lists solutions to some of the earlier lab's exercises, taken from the book Learning Python. Feel free to consult these answers if you get stuck, and also for pointers on alternative solutions. Also see the for answers to additional lab sessions.
Lab 1: Using the Interpreter 1. Assuming your Python is configured properly, you should participate in an interaction that looks something like the following. You can run this any way you like: in IDLE, from a shell prompt, and so on. Note: lines that start with a “%” denote shell-prompt command lines; don’t run these lines at Python’s “ ” prompt, and don’t type either the “%” or “ ” characters yourself—enter just the code after the these prompts. Run “%” shell-prompt commands in a Command Prompt window on Windows, and run “ ” commands in Python (IDLE’s shell window, etc.). You don’t need to run the first command that follows if you’re working only in IDLE, and you may need to use a full “C: Python35 python” instead of just “python” if Python isn’t on your system’s PATH setting. % python # '%' means your shell prompt (e.g., 'C: code').copyright information lines.
'Hello World!' # ' is Python’s prompt: Python code goes here 'Hello World!' # Ctrl-D, Ctrl-Z, or window close to exit 2. Here’s what your code (i.e., module) file and shell interactions should look like; again, feel free to run this other ways—by clicking its icon, by IDLE’s Edit/RunScript menu option, and so on: Note: in this section a “ File: xxx.py” in italics gives the name of the file in which code following it is to be stored, and be sure to always use the parenthesized call form “ print(xxx)” if you’re using Python 3.X (see the for more details). # File: module1.py # enter this code in a new file print 'Hello module world!' # 3.X: use the form print(')% python module1.py # run this command line at a system prompt Hello module world! The following interaction listing illustrates running a module file by importing it.
Remember that you need to reload it to run again without stopping and restarting the interpreter. The bit about moving the file to a different directory and importing it again is a trick question: if Python generates a module1.pyc file in the original directory, it uses that when you import the module, even if the source code file (. Py ) has been moved to a directory not on Python’s search path.
Solutions Manual For Python Program 8e (application/zip)
Pyc file is written automatically if Python has access to the source file’s directory and contains the compiled bytecode version of a module. We look at how this works again in the modules unit. File: module1.py #!/ usr/local/bin/python (or #!/ usr/bin/ env python) print 'Hello module world!' % chmod +x module1.py% module1.py Hello module world! The interaction below demonstrates the sort of error messages you get if you complete this exercise. Really, you’re triggering Python exceptions; the default exception handling behavior terminates the running Python program and prints an error message and stack trace on the screen. The stack trace shows where you were at in a program when the exception occurred (it’s not very interesting here, since the exceptions occur at the top level of the interactive prompt; no function calls were in progress).
In the exceptions unit, you will see that you can catch exceptions using “try” statements and process them arbitrarily; you’ll also see that Python includes a full-blown source-code debugger for special error detection requirements. For now, notice that Python gives meaningful messages when programming errors occur (instead of crashing silently). L = 1, 2 L.append (L) you create a cyclic data-structure in Python. In Python releases before Version 1.5.1, the Python printer wasn’t smart enough to detect cycles in objects, and it would print an unending stream of 1, 2, 1, 2, 1, 2, 1, 2, and so on, until you hit the break key combination on your machine (which, technically, raises a keyboard-interrupt exception that prints a default message at the top level unless you intercept it in a program).
Beginning with Python Version 1.5.1, the printer is clever enough to detect cycles and prints. instead to let you know. The reason for the cycle is subtle and requires information you’ll gain in the next unit. But in short, assignment in Python always generates references to objects (which you can think of as implicitly followed pointers).
When you run the first assignment above, the name L becomes a named reference to a two-item list object. Now, Python lists are really arrays of object references, with an append method that changes the array in-place by tacking on another object reference. Here, the append call adds a reference to the front of L at the end of L, which leads to the cycle illustrated in the figure below. Believe it or not, cyclic data structures can sometimes be useful (but maybe not when printed!). Today, Python can also reclaim (garbage collect) such objects cyclic automatically. A cyclic list Lab 2: Types and Operators 1. Here are the sort of results you should get, along with a few comments about their meaning.
As noted in the exercises, “; ” is used in a few of these to squeeze more than one stamement on a single line (as we’ll learn in the next unit, the semicolon is a statement separator), and comma-separated values display inside parenthesis, because they are really a tuple. L = 1, 2, 3, 4 L 4 Traceback (innermost last): File ', line 1, in? IndexError: list index out of range L -1000:100 1, 2, 3, 4 L 3:1 L 1, 2, 3, 4 L 3:1 = '?' L 1, 2, 3, '?' Indexing, slicing, and del. Your interaction with the interpreter should look something like that listed below. Note that assigning an empty list to an offset stores an empty list object there, but assigning an empty list to a slice deletes the slice.
Slice assignment expects another sequence, or you’ll get a type error; is assigns inserts items inside the sequence assigned, not the sequence itself. L = 1,2,3,4 L2 = L 1, 2, , 4 L2:3 = L 1, 2, 4 del L0 L 2, 4 del L1: L 2 L1:2 = 1 Traceback (innermost last): File ', line 1, in? TypeError: illegal argument type for built-in operation 4. Tuple assignment.
The values of X and Y are swapped. When tuples appear on the left and right of an assignment symbol ( = ), Python assigns objects on the right to targets on the left, according to their positions.
This is probably easiest to understand by noting that targets on the left aren’t a real tuple, even though they look like one; they are simply a set of independent assignment targets. The items on the right are a tuple, which get unpacked during the assignment (the tuple provides the temporary assignment needed to achieve the swap effect).
File = open('myfile.txt', 'w') file.write('Hello file world! N') # or: open.write file.close # close not always needed File: reader.py file = open('myfile.txt', 'r') print file.read # or: print open.read% python maker.py% python reader.py Hello file world!% ls -l myfile.txt - rwxrwxrwa 1 0 0 19 Apr 13 16:33 myfile.txt 12. The dir function: Here’s what you get for lists; dictionaries do the same (but with different method names).
Note that the dir result expanded in Python 2.2—you’ll see a large set of additional underscore names that implement expression operators, and support the subclassing we’ll meet in the classes unit. The methods attribute disappeared in 2.2 as well, because it wasn’t consistently implemented—use dir to to fetch attribute lists today instead. S = 'spam' for c in S. Print ord(c). 115 112 97 109 x = 0 for c in S: x = x + ord(c) # or: x += ord(c).
x 433 x = for c in S: x.append( ord(c)). x 115, 112, 97, 109 map( ord, S) 115, 112, 97, 109 2. Backslash characters. The example prints the bell character ( a) 50 times; assuming your machine can handle it, you'll get a series of beeps (or one long tone, if your machine is fast enough). Hey—I warned you. Sorting dictionaries. Here's one way to work through this exercise; see lecture 3 if this doesn't make sense.
Remember, you really do have to split the keys and sort calls up like this, because sort returns None. Def adder(x, y): return x + y print adder(2, 3) print adder('spam', 'eggs') print adder('a', 'b', 'c', 'd')% python mod.py 5 spameggs 'a', 'b', 'c', 'd' 3.
Two alternative adder functions are shown in the following code. The hard part here is figuring out how to initialize an accumulator to an empty value of whatever type is passed in. In the first solution, we use manual type testing to look for an integer and an empty slice of the first argument (assumed to be a sequence) otherwise. In the second solution, we just use the first argument to initialize and scan items 2 and beyond, much like one of the max function coded in class. The second solution is better (and frankly, comes from students in a Python course I taught, who were frustrated with trying to understand the first solution). Both of these assume all arguments are the same type and neither works on dictionaries; as we saw a priore unit, + doesn’t work on mixed types or dictionaries. We could add a type test and special code to add dictionaries too, but that’s extra credit.
Def adder1(. args): print 'adder1', if type( args0) type(0): # integer? Sum = 0 # init to zero else: # else sequence: sum = args0:0 # use empty slice of arg1 for arg in args: sum = sum + arg return sum def adder2(.
args): print 'adder2', sum = args0 # init to arg1 for next in args1:: sum = sum + next # add items 2.N return sum for func in (adder1, adder2): print func(2, 3, 4) print func('spam', 'eggs', 'toast') print func('a', 'b', 'c', 'd', 'e', 'f')% python adders.py adder1 9 adder1 spameggstoast adder1 'a', 'b', 'c', 'd', 'e', 'f' adder2 9 adder2 spameggstoast adder2 'a', 'b', 'c', 'd', 'e', 'f' 4. Here is our solution to the first part of this one. To iterate over keyword arguments, use a. args form in the function header and use a loop like: for x in args.keys: use argsx. Def adder(good=1, bad=2, ugly=3): return good + bad + ugly print adder print adder(5) print adder(5, 6) print adder(5, 6, 7) print adder(ugly=7, good=6, bad=5)% python mod.py 6 10 14 18 18 5.
Here are our solutions to Exercises 5 and 6. These are just coding exercises, though, because Python has already made them superfluous—Python 1.5 added new dictionary methods, to do things like copying and adding (merging) dictionaries: D.copy , and D1.update(D2). See Python’s library manual or the Python Pocket Reference for more details.
X: doesn’t work for dictionaries, since they’re not sequences. Also remember that if we assign ( e = d ) rather than copy, we generate a reference to a shared dictionary object; changing d changes e too. values = 2, 4, 9, 16, 25 import math res = for x in values: res.append( math.sqrt(x)).
res 1.730951, 2.0, 3.0, 4.0, 5.0 map( math.sqrt, values) 1.730951, 2.0, 3.0, 4.0, 5.0 math.sqrt(x) for x in values 1.730951, 2.0, 3.0, 4.0, 5.0 Lab 5: Modules 1. Basics, import. This one is simpler than you may think. When you’re done, your file and interaction should look close to the following code; remember that Python can read a whole file into a string or lines list, and the len built-in returns the length of strings and lists. Def countLines(name): file = open(name, 'r') return len( file.readlines) def countChars(name): return len(open(name, 'r').read) def test(name): # or pass file object return countLines(name), countChars(name) # or return a dictionary% python import mymod mymod.test ('mymod.py') (10, 291) On Unix, you can verify your output with a wc command; on Windows, right-click on your file to views its properties. (But note that your script may report fewer characters than Windows does—for portability, Python converts Windows “ r n” line-end markers to “ n”, thereby dropping one byte (character) per line.
To match byte counts with Windows exactly, you have to open in binary mode—' rb ', or add back the number of lines.) Incidentally, to do the “ambitious” part (passing in a file object, so you only open the file once), you’ll probably need to use the seek method of the built-in file object. We didn’t cover it in the text, but it works just like C’s fseek call (and calls it behind the scenes): seek resets the current position in the file to an offset passed in. After a seek, future input/output operations are relative to the new position.
To rewind to the start of a file without closing and reopening, call file.seek (0); the file read methods all pick up at the current position in the file, so you need to rewind to reread. Here’s what this tweak would look like.
Import myclient myclient.mymod.countLines from myclient import mymod mymod.countChars In general, you can define collector modules that import all the names from other modules, so they’re available in a single convenience module. Using the following code, you wind up with three different copies of name somename: mod1.somename, collector.somename, and main. Somename; all three share the same integer object initially, and only the name somename exists at the interative prompt as is.
From mod1 import. # collect lots of names here from mod2 import. # from assigns to my names from mod3 import.
from collector import somename 5. Package imports.
For this, we put the mymod.py solution file listed for exercise 3 into a directory package. The following is what we did to set up the directory and its required init.py file in a Windows console interface; you’ll need to interpolate for other platforms (e.g., use mv and vi instead of move and edit ). This works in any directory (we just happened to run our commands in Python’s install directory), and you can do some of this from a file explorer GUI too. When we were done, we had a mypkg subdirectory, which contained files init.py and mymod.py.
You need an init.py in the mypkg directory, but not in its parent; mypkg is located in the home directory component of the module search path. Notice how a print statement we coded in the directory’s initialization file only fires the first time it is imported, not the second. C: python22 mkdir mypkg C: Python22 move mymod.py mypkg mymod.py C: Python22 edit mypkg init.py coded a print statement C: Python22 python import mypkg.mymod initializing mypkg mypkg.mymod.countLines (' mypkg mymod.py') 13 from mypkg.mymod import countChars countChars (' mypkg mymod.py') 346 6. This exercise just asks you to experiment with changing the changer.py example in the book, so there’s not much for us to show here. If you had some fun with it, give yourself extra points. Circular imports. The short story is that importing recur2 first works, because the recursive import then happens at the import in recur1, not at a from in recur2.
The long story goes like this: importing recur2 first works, because the recursive import from recur1 to recur2 fetches recur2 as a whole, instead of getting specific names. Recur2 is incomplete when imported from recur1, but because it uses import instead of from, you’re safe: Python finds and returns the already created recur2 module object and continues to run the rest of recur1 without a glitch. When the recur2 import resumes, the second from finds name Y in recur1 (it’s been run completely), so no error is reported. Running a file as a script is not the same as importing it as a module; these cases are the same as running the first import or from in the script interactively. For instance, running recur1 as a script is the same as importing recur2 interactively, since recur2 is the first module imported in recur1. (E-I-E-I-O!) Lab 6: Classes 1.
Here’s the solution we coded up for this exercise, along with some interactive tests. The add overload has to appear only once, in the superclass, since it invokes type-specific add methods in subclasses. Class Adder: def init(self, start=): self.data = start def add(self, other): # pass a single argument return self.add(other) # the left side is in self def add(self, y): print 'not implemented!' Class ListAdder(Adder): def add(self, y): return self.data + y class DictAdder(Adder): def add(self, y): pass # change me to use self.data instead of x x = ListAdder(1,2,3) y = x + 4,5,6 print y # prints 1, 2, 3, 4, 5, 6 Because values are attached to objects rather than passed around, this version is arguably more object-oriented. And once you’ve gotten to this point, you’ll probably see that you could get rid of add altogether, and simply define type-specific add methods in the two subclasses.
They’re called exercises for a reason! Operator overloading. Here’s what we came up with for this one. It uses a few operator overload methods we didn’t say much about, but they should be straightforward to understand. Copying the initial value in the constructor is important, because it may be mutable; you don’t want to change or have a reference to an object that’s possibly shared somewhere outside the class. The getattr method routes calls to the wrapped list. For hints on an easier way to code this as of Python 2.2, see this unit’s section on extending built-in types with subclasses.
From mylist import MyList class MyListSub( MyList): calls = 0 # shared by instances def init (self, start): self.adds = 0 # varies in each instance MyList. init (self, start) def add (self, other): MyListSub.calls = MyListSub.calls + 1 # class-wide counter self.adds = self.adds + 1 # per instance counts return MyList. add (self, other) def stats(self): return self.calls, self.adds # all adds, my adds if name ' main ': x = MyListSub('spam') y = MyListSub('foo') print x2 print x1: print x + 'eggs' print x + 'toast' print y + 'bar' print x.stats% python mysub.py a 'p', 'a', 'm' 's', 'p', 'a', 'm', 'eggs' 's', 'p', 'a', 'm', 'toast' 'f', 'o', 'o', 'bar' (3, 2) 4. Metaclass methods. We worked through this exercise as follows. Notice that operators try to fetch attributes through getattr too; you need to return a value to make them work. class Meta.
Def getattr(self, name). Print 'get', name. Def setattr(self, name, value). Print 'set', name, value. x = Meta x.append get append x.spam = 'pork' set spam pork x + 2 get coerce Traceback (innermost last): File ', line 1, in? TypeError: call of non-function x1 get getitem Traceback (innermost last): File ', line 1, in? TypeError: call of non-function x1:5 get len Traceback (innermost last): File ', line 1, in?
TypeError: call of non-function 5. Here’s the sort of interaction you should get; comments explain which methods are called. % python from setwrapper import Set x = Set(1,2,3,4) # runs init y = Set(3,4,5) x & y # and , intersect, then repr Set:3, 4 x y # or , union, then repr Set:1, 2, 3, 4, 5 z = Set('hello') # init removes duplicates z0, z-1 # getitem ('h', 'o') for c in z: print c, # getitem. H e l o len (z), z # len repr (4, Set:'h', 'e', 'l', 'o') z & ' mello', z ' mello' ( Set:'e', 'l', 'o', Set:'h', 'e', 'l', 'o', 'm') Our solution to the multiple-operand extension subclass looks like the class below. It needs only to replace two methods in the original set. The class’s documentation string explains how it works.
From setwrapper import Set class MultiSet(Set): ' inherits all Set names, but extends intersect and union to support multiple operands; note that 'self' is still the first argument (stored in the. args argument now); also note that the inherited & and operators call the new methods here with 2 arguments, but processing more than 2 requires a method call, not an expression: ' def intersect(self,.others): res = for x in self: # scan first sequence for other in others: # for all other args if x not in other: break # item in each one? Else: # no: break out of loop res.append(x) # yes: add item to end return Set(res) def union(. args): # self is args0 res = for seq in args: # for all args for x in seq: # for all nodes if not x in res: res.append(x) # add new items to result return Set(res) Your interaction with the extension will be something along the following lines. Note that you can intersect by using & or calling intersect, but must call intersect for three or more operands; & is a binary (two-sided) operator. Also note that we could have called MutiSet simply Set to make this change more transparent.
If we used setwrapper.Set to refer to the original within multiset. from multiset import. x = MultiSet(1,2,3,4) y = MultiSet(3,4,5) z = MultiSet(0,1,2) x & y, x y # 2 operands ( Set:3, 4, Set:1, 2, 3, 4, 5) x.intersect (y, z) # 3 operands Set: x.union (y, z) Set:1, 2, 3, 4, 5, 0 x.intersect (1,2,3, 2,3,4, 1,2,3) # 4 operands Set:2, 3 x.union (range(10)) # non- MultiSets work too Set:1, 2, 3, 4, 0, 5, 6, 7, 8, 9 6. Our solution is below, with comments from the description mixed in with the code.
This is one case where it’s probably easier to express a problem in Python than it is in English. File: zoo.py class Animal: def reply(self): self.speak # back to subclass def speak(self): print 'spam' # custom message class Mammal(Animal): def speak(self): print 'huh?' Class Cat(Mammal): def speak(self): print 'meow' class Dog(Mammal): def speak(self): print 'bark' class Primate(Mammal): def speak(self): print 'Hello world!' Class Hacker(Primate): pass # inherit from Primate 8.
The Dead Parrot Skit. Here’s how we implemented this one. Notice how the line method in the Actor superclass works: be accessing self attributes twice, it sends Python back to the instance twice, and hence invokes two inheritance searches— self.name and self.says find information in the specific subclasses. We’ll leave rounding this out to include the complete text of the Monty Python skit as a suggested exercise. Class Actor: def line(self): print self.name + ':', repr( self.says) class Customer(Actor): name = 'customer' def says(self): return 'that's one ex-bird!' Class Clerk(Actor): name = 'clerk' def says(self): return 'no it isn't.'
Class Parrot(Actor): name = 'parrot' def says(self): return None class Scene: def init(self): self.clerk = Clerk # embed some instances self.customer = Customer # Scene is a composite self.subject = Parrot def action(self): self.customer.line # delegate to embedded self.clerk.line self.subject.line Lab 7: Exceptions and built-in tools 1. Our version of the oops function follows. As for the noncoding questions, changing oops to raise KeyError instead of IndexError means that the exception won’t be caught by our try handler (it “percolates” to the top level and triggers Python’s default error message). The names KeyError and IndexError come from the outermost built-in names scope. If you don’t believe us, import builtin and pass it as an argument to the dir function to see for yourself.