Python in a Nutshell, Second Edition by Alex Martelli The unconfirmed error reports are from readers. They have not yet been approved or disproved by the author or editor and represent solely the opinion of the reader. 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 This page was updated August 1, 2008. UNCONFIRMED errors and comments from readers: (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! (xi) Last paragraph; Missing word: "...how **TO** use "cookies" to deal with..." (4) 4th paragraph; If you find you are [MORE???] productive with Java or C# than with C or Fortran... {49} 3rd paragraph; The mathematical nature of this excellent book brings out the nitpickiest elements of the mathematician in me. 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__. {56} second group of examples; The book says: x[1:4]=[8,9] # x is now [1,8,9,4] But it should say: x[1:4]=[8,9] # x is now [1,8,9] (80) paragraph 4, 6; RecursionLimitExceeded is not a standard exception. A RuntimeError with the message "maximum recursion depth exceeded" is raised instead. [82] 6th paragraph, Static Methods; In the discussion of static methods, the book says: A static method may have any signature: it may have no arguments, and the first argument, if any, plays no special role. The first part of the sentence contradicts the rest of it. It should probably read: it may have *any* arguments, and the first argument, if any, plays no special role. I tested it with python 2.4.4, and a static method can have any number of arguments. This refers to 8/05 edition of the book, but I didn't see this error mentioned in the errata list of any of the subsequent editions. {87} 2nd paragraph; Here, the book says:"When __init__ is absent, you must call the class without arguments, and the newly generated instance has no instance-specific attributes." I find this incorrect. For example, consider the code snippet below: >>> class A(object): def __init__(self,x): self.x=x >>> class B(A): pass >>> b1=B() Traceback (most recent call last): File "", line 1, in b=B() TypeError: __init__() takes exactly 2 arguments (1 given) >>> b2=B(23) >>> b2 <__main__.B object at 0x012927B0> >>> b2.x 23 The mistake corresponds to the issue of "class inheritance". (87) Example says: ''' class C7: pass z = C7( ) z.x = 23 print z.x # prints: 23 [snip] In this case, the statement z.x=23 executes type(z).x._ _set_ _(z, 23) (old-style instances ignore the overriding nature of descriptors found in their classes, i.e., they never call their _ _set_ _ methods). ''' I find this confusing because actually in this case __set__ is /not/ executed: a) class C7 has no x attribute or __set__ method b) even if it did, it's an old-style class so __set__ wouldn't get called (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. (100) Classmethod example; Example should read: class ABase(object): def aclassmet(cls): print 'a class method for', cls._ _name_ _ aclassmet = classmethod(aclassmet) class ADeriv(ABase): pass bInstance = ABase( ) dInstance = ADeriv( ) ABase.aclassmet( ) # prints: a class method for ABase bInstance.aclassmet( ) # prints: a class method for ABase ADeriv.aclassmet( ) # prints: a class method for ADeriv dInstance.aclassmet( ) # prints: a class method for ADeriv {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. {110} Code example at bottom; The text accurately describes a slice object has having a method called 'indices'. In the code example, however, the invoking object is not a slice. E.g., The author intended: return self.__class__(self[x] for x in xrange(*index.indices(len(self)))) instead of: return self.__class__(self[x] for x in xrange(*self.indices(len(self))) # the latter is also missing the final closing # parenthesis {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. {166} End of 'reduce' section; result of reduce() is the product of a sequence of numbers, but it is getting bound to 'thesum'. {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 {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). (183) Third attribute description, "cycle"; Syntax summary is "count(iterable)", should be "cycle(iterable)" (187) 3rd section; The string method 'decode' which was introduced in Python 2.2 is missing. http://docs.python.org/lib/string-methods.html (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". (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)). """ {198} 1st paragraph describing the repr Module; Change: the built-in function repr (covered in repr on page 198) to: the built-in function __repr__ (covered in __repr__ in page 108) (207) first code snippet; The third line of code is wrapping down, it must not. (231) first code snippet; The third line of code is wrapping down, it must not. (305) Near bottom of page in strptime discussion; strptime discussion referrs to the time format table for strftime being on page 304, but the table is in fact on the same page, 305. {307} strftime; fmt parameter is missing in function prototype. (310) 5th method description; The method name, in the syntax description, says "d.timezone(tz)", it should say "d.astimezone(tz)". {311} strftime; fmt argument missing from prototype. {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. {356} 3rd paragraph under popen2 : "File objects ..."; Quote: "In other words, there is no way in which the caller of popen2, popen3, or popen4 can learn about P's termination code." "no way" is a bit harsh here. You can get it with python tools if you set a signal handler for SIGCHLD and reap the childinfo with wait* calls. {449} Events example; it uses both "Import Tkinter" and "from Tkinter import *". The first is unnecessary and would be incorrect if the other was removed. (458) 2nd paragraph under Example 18-2; method 'testExactly1Argument' referred to in paragraph is actually testExactlyOneArgument in Example 18-2 {458} second def statement in example 18-2; the second instance of 'justoneword' should be reversed: self.assertEqual(mod.reverseWords('justoneword'), 'justoneword') should be: self.assertEqual(mod.reverseWords('justoneword'), 'drowenotsuj') {486} First two paragraphs; 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]) {511} 1st paragraph after "Network News" title; It talks about POP protocol, and should talk about NNTP protocol. {518} end; 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: " (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) (541) 3rd reactor method description, connectTCP; The syntax description says "r.listenTCP(", should be "r.connectTCP(" (695) lower right quadrant; The index refers the reader to page 76 for information on 'yield'. There is no useful information on yield on that page, but there is on page 78.