Python in a Nutshell, Second Edition by Alex Martelli This errata page lists errors corrected in the digital version. If you have technical questions or error reports, you can send them to booktech@oreilly.com. Please specify the printing date of your copy. This page was updated July 10, 2008. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification Confirmed errors: (5.3 - On Safari Only) Last example; Decorators should be on line by themselves. Example should read: def showdoc(f): if f._ _doc_ _: print '%s: %s' % (f._ _name_ _, f._ _doc_ _) else: print '%s: No docstring!' % f._ _name_ _ return f @showdoc def f1( ): "a docstring" # emits: f1: a docstring @showdoc def f2( ): pass # emits: f2: No docstring! AM: reader's right regarding online (Safari) only - line break needed after each '@showdoc' and absent on Safari only -- however indentation within showdoc itself is correct on Safari and wrong here. (xi) Last paragraph; Missing word: "...how **TO** use "cookies" to deal with..." AM: reader's right, s/how use/how to use/ (4) 4th paragraph; If you find you are [MORE???] productive with Java or C# than with C or Fortran... AM: reader's right, s/productive/more productive/ {49} 3rd paragraph; The sentence "For example, x=x+y does not modify the object to which name x was originally bound" is incorrect, I think. Suppose x and y belong to a user-defined class in which __add__ has been defined. Suppose __add__(self, other) changes some attribute (say 'value') of self. Suppose we make the statements: z=x x = x+y print z.value The point of the discussion in the book is that x is reassigned, not changed in place. However, the object originally bound to x will be changed in place, and that change can be seen here in z. The introduction of a custom __add__ is not so out of left field here, since the book is contrasting the situation to when the object has a custom __iadd__. AM: substitute /For example, x=x+y/For example, the assignment in x=x+y/ . (80) paragraph 4, 6; RecursionLimitExceeded is not a standard exception. A RuntimeError with the message "maximum recursion depth exceeded" is raised instead. AM: reader's right; s/RecursionLimitExceeded exceptions/"maximum recursion depth exceeded" exceptions/ (87) Attributes of instance objects paragraph; Class C7 is an old-style class. The author always used new style ones in the first part of the chapter. AM: The slight style variation can be fixed by s/class C7: pass/class C7(object): pass/ {110} Example at bottom of page; In the __getitem__ example, self.indices should be index.indices; also, one parenthesis seems to be missing at the end. AM: reader's right on both accounts, s/self.indices/index.indices/ AND add a ) at the end of that same line {165} In 'ord' section; The integer code returned for unicode is [0,65534], but shouldn't it be 65535? But if it cannot return 65535, I would have appreciated knowing why it wouldn't. AM: reader's right, s/65534/65535/ {166} End of 'reduce' section; result of reduce() is the product of a sequence of numbers, but it is getting bound to 'thesum'. AM: reader's right, to reduce confusion s/thesum/theprod/ {175} 2nd paragraph; >>> import collections, operator >>> def sorted_histograms(seq): d = collections.defaultdict(int) for item in seq: d[item] += 1 print d return sorted(d.iteritems, key=operator.itemgetter(1), reverse=True) >>> a = [ "b", "c", "d", "b", "c", "c", "e", "d"] >>> b = sorted_histograms(a) defaultdict(, {'c': 3, 'b': 2, 'e': 1, 'd': 2}) Traceback (most recent call last): File "", line 1, in b = sorted_histograms(a) File "", line 9, in sorted_histograms return sorted(d.iteritems, key=operator.itemgetter(1), reverse=True) TypeError: 'builtin_function_or_method' object is not iterable >>> b Traceback (most recent call last): File "", line 1, in b NameError: name 'b' is not defined AM: reader's right, s/sorted(d.iteritems, /sorted(d.iteritems(), / {177} Description of heappop; Doesn't heappop run in O(log(len(alist))) time instead of O(len(alist))? If it was O(len(alist)), then heapsort would be O(n^2). AM: reader's right, s/O(len(alist))/O(log(len(alist)))/ (183) Third attribute description, "cycle"; Syntax summary is "count(iterable)", should be "cycle(iterable)" AM: reader's right, s/count/cycle/ (187) 3rd section; The string method 'decode' which was introduced in Python 2.2 is missing. http://docs.python.org/lib/string-methods.html AM: reader's right. Just before 'encode' where it alphabetically belongs, with s/encode/decode/ in the syntax summary as well, and short description Returns a (typically unicode) string obtained from s with the given coded and error handling. See "Unicode" on page 198 for more details. i.e. basically the same as encode except for the parenthetical note that the result is typically Unicode. Maybe the apparent duplication is what caused the snip...? (189) Description of rstrip; Text reads "Returns a copy of s, removing leading characters that are found in string x" but should read "trailing" instead of "leading". AM: reader's right, s/leading/trailing/ (197) 3rd paragraph (if we count the examples as a paragraph); It explains "textwrap.fill". It says that... """ Returns a single multiline string that is exactly equal to '\n'.join(fill(s,width)). """ ... and it should say ... """ Returns a single multiline string that is exactly equal to '\n'.join(wrap(s,width)). """ AM: Reader's right, s/fill/wrap/ (207) first code snippet; The third line of code is wrapping down, it must not. AM: reader's right, break the line typographically right after the colon ':' and put 'print' etc on the NEXT typographical line indented four spaces (231) first code snippet; The third line of code is wrapping down, it must not. AM: reader's right, put a \ at the end of the third line and indent the following (fourth) line four spaces {307} strftime; fmt parameter is missing in function prototype. AM: reader's right, s/d.strftime()/d.strftime(fmt)/ (310) 5th method description; The method name, in the syntax description, says "d.timezone(tz)", it should say "d.astimezone(tz)". AM: reader's right, s/timezone/astimezone/ {311} strftime; fmt argument missing from prototype. AM: reader's right, s/d.strftime()/d.strftime(fmt)/ {312} example usage for timedelta; The second timedelta() call in the "print repr(timedelta...)" examples should be changed from timedelta(minutes=0.5) to timedelta(hours=-1) for the example output to be correct. AM: reader's right, s/minutes=0.5/hours=-1/ in that second example. (458) 2nd paragraph under Example 18-2; method 'testExactly1Argument' referred to in paragraph is actually testExactlyOneArgument in Example 18-2 AM: reader's right, s/testExactly1Argument/testExactlyOneArgument/ in that text {485} Last code section; The example in this section was how to quickly sort a list of strings based on the second word in each string. The operator.itemgetter technique incorrectly sorts based on the second character in each string, not the second word. Maybe use something like: L.sort(key=lambda x: x.split()[1]) AM: reader's right that the code at the almost-bottom of p.485 is incorrect, but the right fix is to change those two lines into the following two lines instead: def secondword(s): return s.split()[1] L.sort(key=secondword) {511} 1st paragraph after "Network News" title; It talks about POP protocol, and should talk about NNTP protocol. AM: reader's right, s/POP/NNTP/ {518} Bottom of page Example program produces error message: "Traceback (most recent call last): File "C:\xmlrpctest.py", line 6, in results = proxy.meerkat.getItems({'search':'Python', 'num_items':7}) File "C:\Python25\Lib\xmlrpclib.py", line 1147, in __call__ return self.__send(self.__name, args) File "C:\Python25\Lib\xmlrpclib.py", line 1437, in __request verbose=self.__verbose File "C:\Python25\Lib\xmlrpclib.py", line 1191, in request headers ProtocolError: " AM: reader's right, Meerkat is no longer available and was shut down March 2, 2006. Delete example. (524) Middle of page, End of 3rd paragraph; getsockopt example reads: import socket s = socket.socket() print s.getsockopt(s.SOL_SOCKET, s.S0_REUSEADDR) Code should read: import socket s = socket.socket() print s.getsockopt(socket.SOL_SOCKET, socket.S0_REUSEADDR) AM: Reader's right, pls change as he's indicated (except it's SO_REUSEADDR as in the book, not S0_REUSEADDR as he indicates -- an uppercase O, *not* a zero digit). (541) 3rd reactor method description, connectTCP; The syntax description says "r.listenTCP(", should be "r.connectTCP(" AM: Reader's right, s/listenTCP/connectTCP/