Errata

Python in a Nutshell

Errata for Python in a Nutshell, Fourth Edition

Submit your own errata for this product.

The errata list is a list of errors and their corrections that were found after the product was released. If the error was corrected in a later version or reprint the date of the correction will be displayed in the column titled "Date Corrected".

The following errata were submitted by our customers and approved as valid errors by the author or editor.

Color key: Serious technical mistake Minor technical mistake Language or formatting error Typo Question Note Update

Version Location Description Submitted By Date submitted Date corrected
Page Page 457
Table 15-9 (SimpleQueue part)

In Table 15-9, the SimpleQueue is described as "an unbounded FIFO queue lacking the methods full, task_done, and join (see Table 15-10)" which suggests that these methods are listed in 15-10, but only the method full is listed there. The task_done and join methods are only explained in the text surrounding the table.

Note from the Author or Editor:
Thanks for submitting. In many of the tables in the book, we could not list every related item for each class or module, else the book would easily exceed 900 pages. And so we would choose selected items to include, and direct the reader to online resources for more complete docs; that is the case for this table as well.

To help minimize the confusion described in this erratum, we propose changing the description in Table 15-9 to "an unbounded FIFO queue lacking the methods full, task_done, and join (see Table 15-10 and the following text)".

Ivo Grondman  Mar 07, 2023 
Page p156
last section

in methods list, missing method `__rtruediv__` after `__radd__`

Note from the Author or Editor:
The list of method names should read in this order:
__radd__, __rfloordiv__, __rmod__, __rmul__, __rsub__, __rtruediv__, __rmatmul__

In the description, the first sentence should start "The operators y+x, y//x, y%x, y*x, y-x, y/x, y@x respectively call these methods on x..."

Tim Stamp  Aug 25, 2023 
Page 42 and 698
P. 42 — 2nd row of Table 3-2; p. 698 — Index

Underscore in “from_hex” should be removed, so that the resultig name of this method will be “fromhex”. This relates to three instances of “from_hex” on p. 42 and to one — on p. 698.

Note from the Author or Editor:
Replace "from_hex" with "fromhex" in 3 places on p. 42 and in index.

Vadim Flyagin  Aug 01, 2024 
Page 43
Paragraph entitled “Sequences”

This paragraph contains a reference to the same page on which it is printed: “as discussed in “Sequences” on page 43” ”. Two typose are here: 1) the sign of the closing quote (”) after the number “43” is not matched and so should be deleted; 2) this page (i. e. 43) does not contain information to which this reference points (“Library and extension modules provide other sequence types, and you can write others yourself”), so I guess that the page number to which this reference points should be changed, or, alternatively, the reference should be deleted if case when there is no such information in the book.

Note from the Author or Editor:
The authors' intention was to refer to the section titled "Sequences" in Chapter 4, page 147 in the printed version.

Change the contents in parentheses to read '(as discussed in "Sequences" on page 147)`

Vadim Flyagin  Jul 30, 2024 
Page 49
5th paragraph

Book states: "If a key's value appears more than once in a dictionary expression, only an arbitrary one of the items with that key is kept in the resulting dictionary object -- dictionaries do not support duplicate keys."

Official python docs (at both the current 3.12.4 version and 3.7) state: "If a key occurs more than once, the last value for that key becomes the corresponding value in the new dictionary." Later on, it is mentioned that keyword arguments are incorporated in the same way - after the iterable/mapping argument.

Note from the Author or Editor:
Replace cited sentence with:

Dictionaries maintain their keys in the order that they are inserted. If a key appears more than once in a dictionary expression, the first occurrence of that key determines the key's position in the dictionary’s iteration order. But only the last value for that key is kept in the resulting dictionary object - dictionaries do not support duplicate keys. (For a dictionary-type class that stores multiple values for a given key, see the defaultdict(list) example on page 267.)

Matt Belland  Jul 25, 2024 
Page 51
3rd paragraph

Book: "Generators are also callable"

Due to the terminology confusion explained on page 109, it would be more accurate to say "Generator functions are also callable"

Note from the Author or Editor:
Change "Generators are also callable" to "Generator functions are also callable"

Matt Belland  Jul 25, 2024 
Printed, O'Reilly learning platform
Page 59
Code example beginning with "re_match ="

Regular expression should be `r'Name: (\S+)` to capture a full name (currently just captures the first character). Occurs in 2 places in this code example.

Paul McGuire
 
Nov 26, 2023 
Page 126
2nd title

This section would be better titled without reference to "Unbound Objects". Unbound methods were a 3rd form of method in python2, in addition to bound methods and function objects.

Note from the Author or Editor:
Change section title to just "Bound Methods".

Matt Belland  Aug 01, 2024 
Page 127
5th paragraph

The bound method read-only attributes im_class, im_func, and im_self were removed in the transition to Python 3. im_class was replaced by __self__, im_func was replaced by __func__, and im_class does not have a direct replacement, but class information can be inferred from __func__.__qualname__ or from the instance's __class__.

Note from the Author or Editor:
Replace paragraph with:

A bound method has two readonly attributes in addition to those of the function object it wraps: __func__ is the wrapped function, and __self__ refers to x, the object from which you got the method.

Matt Belland  Aug 01, 2024 
Page 135
code

You don't need to print(AClass.astatic()), as that method already prints the desired output. The extra print() calls in this line and the next result in a couple of 'None' lines being printed to the output.

Note from the Author or Editor:
Remove print() function calls in last 2 lines of the code example, so that the last 3 lines read:

an_instance = AClass()
AClass.astatic() # prints: a static method
an_instance.astatic() # prints: a static method

Matt Belland  Aug 01, 2024 
Page 254
table entry for "filter" function

Parantheses are not "paired":

(item for item in seq if func(item)

either missing closing, or opening paranthesis is unnecessary.

Note from the Author or Editor:
Thanks for submitting this. We should add a closing parenthesis at the end of this line, so that it reads "(item for item in seq if func(item))".

Marek Włodarz  Sep 05, 2023 
Printed
Page 256
Description of "map()" function

The code examples for map() read as:
-------
For example, map(func, seq) is just like the generator expression:

(func(item) for item in seq).map(func, seq1, seq2)

is just like the generator expression:

(func(a, b) for a, b in zip(seq1, seq2))
-------


The first snippet is in error, and should be merged with the intervening text, as follows:
-------
For example, map(func, seq) is just like the generator expression:

(func(item) for item in seq)

map(func, seq1, seq2) is just like the generator expression:

(func(a, b) for a, b in zip(seq1, seq2))
-------



Paul McGuire
 
Dec 11, 2023 
Printed
Page 262
Code fragment for ps1,ps2

Classes Ps1 and Ps2 are defined as inheriting from object, this is no longer necessary in Python 3 and should be removed.

Just declare them as

class Ps1:
... with remaining code ...

class Ps2:
... with remaining code ...

Paul McGuire
 
Dec 11, 2023 
Printed
Page 273
Code example beginning with "import heapq"

Class KeyHeap is defined as inheriting from object. This is a legacy from Python 2, no longer required in Python 3. The first line of the class declaration should be:

class KeyHeap:

Paul McGuire
 
Dec 11, 2023 
Printed
Page 284
Table of str methods

Omitted entries for str.partition and str.rpartition.

Consider merging all the is* methods and r* methods into consolidated entries to save table space.

Paul McGuire
 
Apr 25, 2024 
Printed
Page 289
Code example starting with ">>> name = 'Dawn'"

The second line of the example reads:

>>> print('{name} is {n} characters long'

In the following example output, Dawn is enclosed in single quotes. To get this, the example print statement should be:

>>> print('{name!r} is {n} characters long'

Paul McGuire
 
Dec 11, 2023 
Page 471
Code snippet on that page

The code on this page isn't safe to be called from multiple threads. For example, this code will occasionally detect errors where some results are returned "out of order".

def test_serializer():
"""Tests the Serializer class."""
serializer = Serializer()

def f(ii):
expected = ii*ii
actual = serializer.apply(lambda x: x * x, ii)
if actual != expected:
print(f"{expected=}, {actual=}")

for i in range(10):
threading.Thread(target=f, args=(i,)).start()

test_serializer()

The Serialiser is fine if there is only ever one calling thread, putting tasks on the queue for the other thread to execute. The race condition occurs when multiple threads are invoking apply() simultaneously, in which case it's possible for any given invocation to return the result from another thread's invocation.

Note from the Author or Editor:
I replicated the reported issue, the submitter is correct. Need to confer with co-authors to compose a suitable correction to this code example.

Update 13 Jan 2024 - after reviewing with co-authors, we have updated this code example to use type-safe data structures (view changes in the Github repository) - great catch, thanks!

Dave Slotnick  Nov 15, 2023 
Page 578
Code block, 4th last line

"cconcurrent.futures" instead of "concurrent.futures"

Note from the Author or Editor:
This is a typo in the source of the example code on this page.

with cconcurent.futures.ThreadPoolExecutor(20) as e:

Should be:

with concurent.futures.ThreadPoolExecutor(20) as e:

Tim Stamp  Sep 25, 2023 
Page 674 - What's new in Python 3.8
2nd line of table, after headers

The entry lists "Positional-only and named-only parameters (/ and * arg separators)". Only positional-only arguments (/ symbol in function signature) are new in Python 3.8 - see PEP-570. Keyword-only arguments (* symbol) were introduced back in Python 3.0 - see PEP-3102.

Note from the Author or Editor:
Thank you for submitting! The wording in the table should be changed to read "Positional-only '/' argument separators", since '*' argument separators were already supported as of Python 3.0. We'll also revisit the text on pp.95-97 to make sure that version markers are correctly placed.

Matt Morrison  May 01, 2023 
Printed
Page 681
entry for enum.StrEnum

enum.StrEnum was erroneously listed in the table of changes in Python 3.10, but this change was not actually made until Python 3.11. This entry should be moved to the table for Python 3.11 (approx. p. 684)

Affects all versions and translations of this book.

Paul McGuire
 
Nov 16, 2023