Python Cookbook by Alex Martelli, Anna Martelli Ravenscroft & David Ascher 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 July 31, 2008. UNCONFIRMED errors and comments from readers: {5} third code example; 1) A blank space should precede the backslash in line 1. 2) This code doesn't seem to work unless line 2 starts at column 1, thus breaking indentation rules. class TestText: def test_multiple_lines(self): big = "This is a long string \ that spans two lines." assert big == 'This is a long string that spans two lines.', \ 'Error for %s' % big (test_text.TestText.test_multiple_lines ... ok) {68} 2nd and 3rd line; The code reads output.close() instead of output_file.close() and input.close() instead of input_file.close() This results in the following error: Traceback (most recent call last): File "./replace", line 18, in output.close() NameError: name 'output' is not defined {96} comments in the code (Solution) of recipe 2.22, second function called 'common_prefix'; I may have found something worth correcting and would like to share it with you. The apparent mistake can be found on page 96 in the comments in the code (Solution) of recipe 2.22 "Computing the relative path from one directory to another". The comments on the code refer to "unique tails", this statement isn't always true. There are several ways in which the resulting tails would not be unique. This is an example to illustrate this: >>> li1 = [1,2,3,4] >>> li2 = [1,2,4,5] >>> li3 = [1,2,4,5] >>> common_prefix(li1, li2, li3) ([1, 2], [[3, 4], [4, 5], [4, 5]]) As you may see the second element in the tuple - the list containing the 'tails' - contains the 'tail' [4, 5] twice. I'm using numbers here for the sake of the example but for paths the same is off course true. [124] Recipe 3.6; Boxing day is the day after Christmas, not the day after Easter. {132} code snippet "if numargs < 3"; By the time this statement is executed we had already determined that there must be either 1 or 2 command line args passed in otherwise the script would have exited. However now we are checking whether numargs < 3 where numargs = len(sys.argv) - 1. This condition will always be true i.e. if len(sys.argv) = 3 then numargs = 2 and numargs will always be less than 3, therefore the else clause will never be executed AFAICT. (166) 1st paragraph; About the timing of the different "Adding an Entry to a Dictionary" algorithms, you write, "Taking the first version of addword in the recipe as a reference point, the second one (using try/except) is about 10% faster, the third one (using setdefault) is about 20% slower[.]" But the order of the definitions on the previous page is setdefault first, if/else second, and try/except third. {201/202} Code; The return value of the hist.counts method in the code snippet is just the list of keys sorted by values. However, on the example on the next page at the bottom it's outputting keys and value combinations. [240] Recipe 6.3; Recipe 6.3 doesn't (seem to) work because the overrridden __setattr__ also operates during __init__ i.e. you cannot set any attributes at all... [271] code in solution to 6.15; The line cls._inst = type.__new__(cls, *args, **args) should read cls._inst = object.__new__(cls, *args, **args) (272) 1st code block, first and third lines from bottom; Instance objects s1 and s2 have no method 'spam()', therefore these two line will cause AttributeError. Do the authors intend to print 's1.s' and 's2.s' instead of 's1.spam()' and 's2.spam()'? [353] first code example, 7th line; if not (second-error) < first < (second-error): should read: if not (second-error) < first < (second+error): {413} in code sample, beginning of page; wr.SetValueEx(..., REG_SZ,..) => wr.REG_SZ after both finally: CloseKey(...) => wr.CloseKey(...) {449} Near the middle of the Solution code listing; for k, v in kw: should be for k, v in kw.iteritems(): [472] Recipe 12.5 code: class Xml2Obj, func EndElement; In this code: def EndElement(self, name): 'Expat end element event handler' self.nodeStack[-1].pop( ) the last line is wrong. It should read: self.nodeStack.pop( ) [495] python code sample at bottom of page; line 3 of example: import mimetypes, email.Generator, email.Message line 10 of example: mainMsg = email.Message.Message( ) results in: Traceback (most recent call last): File "/home/f85/noonan/bin/gradetools/htmlmail.py", line ?, in ? mainMsg = email.Message() AttributeError: 'dict' object has no attribute 'Message' [561] solution code; Server references meerkat which is no longer available. [562] first code snippet and paragraphs before and after; The "main point" described here appears to be completely wrong. The book says "...an instance object with the right attributes works just as well as a dictionary object..." But the documentation for xmlrpclib says "Note that even though starting with Python 2.2 you can subclass builtin types, the xmlrpclib module currently does not marshal instances of such subclasses." The docs are right. The implementation of xmlrpclib dispatches function parameters using type(value), not isinstance(value), so it can't handle anything but its short list of known (built-in) types. The variant code on this page just prints: TypeError: cannot marshal objects {712} the cross_loop() function; 1 def cross_loop( *sequences ) : 2 # from _Python Cookbook_, 2e pg 712 3 if sequences : 4 for x in sequences[0] : 5 for y in cross_loop( *sequences[1:] ) : 6 yield (x,) + y 7 else : 8 yield () I added the "*" to the cross_loop() call in line 5. Otherwise, I think, the bare sequences[1:] would pass the slice into the recursive call to cross_loop(). The inner calls' sequences would then be a length 1 array containing the tuples from the slice. I'm not too sure I wasn't simply calling the function incorrectly. def cross_product( self ) : return cross_loop( self.y_radius_range, self.cbcr_radius_range, self.scale_10_range, self.scale_15_range, self.scale_20_range, self.output_scale_range ) All those "_range" members are tuples of integers. An eventual simplification was: def cross_product( self ) : sequences = [] for f in self.iterable_field_names : sequences.append( getattr( self, f+"_range" ) ) return cross_loop( *sequences ) Both of those functions worked when I added the "*" to the front of the sequences[1:] slice in the recursive call.