Errata of Expert Python Programming book

If you find an errata, please connect with feedback/feedback and fill a ticket.

page 13

Typos :

on ubuntu, it's the build-essential package (without s). And the last command, there is "tar -xzvf" twice. Only one is necessary of course.

Reported by Vincent Fretin

page 45

1g1e1t1 8u1p on bottom of the page should be 1g1e1t1 18u1p

Reported by Chaim Krause

page 50 and 51

The variable called rpc_info in page is called rpc_infos in page 51. It needs to be rpc_info everywhere.

page 55

>>> @locker
... def thread_safe():
...     pass
... 

2 typo, this should be:

...
>>> @synchronized
... def thread_safe():
...     pass
... 

(Notice the extra '...' before '>>> @synchronized'

Reported by Dirk Loss

page 56

Typo in:

from __future__ import with_statement 
with file('/etc/hosts') as hosts: 
    for line in hosts: 
        if line.startswith('#'): 
            continue 
        print host

The last line should be "print line":

from __future__ import with_statement 
with file('/etc/hosts') as hosts: 
    for line in hosts: 
        if line.startswith('#'): 
            continue 
        print line

page 60

After the word "example" and prior to the comma, there is an extra space.

page 64

The traceback :

"ValueError: This value already exists for 'value'"

Should be:

"DistinctError: This value already exists for 'value'"

Reported by Dirk Loss

page 69

"The tail is the first element of a list and head contains rest of the elements."

This should be:

"The head is the first element of a list and tail contains the rest of the elements."

Reported by Dirk Loss

page 75

Algorithm for getting attribute is not right. A copy-paste error appear during editing.

It should be:

# 1- looking for definition
if hasattr(MyClass, 'attribute'):
    attribute = MyClass.attribute
    AttributeClass = attribute.__class__

    # 2 - does attribute definition have a getter ?	
    readable = hasattr(AttributeClass, '__get__')

    # 3 - does attribute definition have a setter,
    #     or 'attribute' is not found in __dict__
    writable = (hasattr(AttributeClass, '__set__') or 
                'attribute' not in instance.__dict__)

    if readable and writable:
        # 4 – let’s call the descriptor 
        return AttributeClass.__get__(attribute,
                                      instance, MyClass)

# 5 - regular access with __dict__
return instance.__dict__['attribute']

page 76

In the middle of the page, the example:

MyClass.new_att = MyDescriptor()

should be:

MyClass.new_att = UpperString()

page 94

The example has one important flaw: constants' values change if their definitions change order in source file. Even more crucially, inserting a constant definition in between existing ones will change the values for all those shifting down. This may become a problem during upgrades, when two instances of the same program have to send each other serialized data, or when data are saved and later restored.

If we start here...

OPTIONS = {}
def register_option(name):
    return OPTIONS.setdefault(name, 1 << len(OPTIONS))

BLUE = register_option('BLUE')
RED = register_option('RED')
BLUE, RED
 (1, 2)

...but later commit a new option like this...

OPTIONS = {}
def register_option(name):
    return OPTIONS.setdefault(name, 1 << len(OPTIONS))

BLUE = register_option('BLUE')
GREEN = register_option('GREEN')
RED = register_option('RED')
BLUE, RED
 (1, 4)

...we end up with a different value for RED.

At least a warning about this potential problem would be nice to have.

Something like a new box at the bottom of the page, saying:

Beware that this technique has one important pitfall : constants' values 
change if their definitions change order in source file. So you will
need to append new constants at the end of the list and not change their 
ordering. 

Reported by Sergey Lipnevich.

page 105

This example::

>>> def sum(sequence):
...     total = 0
...     for arg in args:
...         total += arg
...     return total
... 

Should be:

>>> def sum(sequence):
...     total = 0
...     for arg in sequence:
...         total += arg
...     return total
... 

Reported by Dirk Loss

page 111

There's a typo in the following fragment: "it is more that 500 lines"

The correct contents should be "it is more than 500 lines" where that has been substituted by than.

page 114

Windows doesn't define HOME, but it does define USERPROFILE, or the value returned by os.path.expanduser('~') in Python.

So it should be:

Under Windows, ... (See the USERPROFILE environment variable, or the value returned by os.path.expanduser('~') in Python.)

Reported by Sergey Lipnevich.

page 137

Typo in first line. Instead of "pbp.skeles" it should be "pbp.skels".

page 154

"Each item is a dictionnary that contain the entry::"

Should be:

"Each item is a dictionary that contains the entry::"

Reported by Dirk Loss

page 258

suite is redefined in test_suite() and that causes an error.

TestCases and TestSuites must be instantiated before passing them to addTest()

Here is the modified code:

def test_suite():
    """builds the test suite."""
    def _suite(test_class):
        return unittest.makeSuite(test_class)
    suite = unittest.TestSuite()
    suite.addTests((_suite(MyTests), _suite(MyTests2)))
    return suite

Reported by Chaim Krause

Page 281

The last column of the example output in the middle of the page shows:

myapp.py:3(lighter)
myapp.py:6(light)
myapp.py:9(heavy)

This is a typo, it should be:

myapp.py:3(medium)
myapp.py:6(light)
myapp.py:9(heavy)

Reported by Dirk Loss

page 300

Broken link:

http://pages.cs.wisc.edu/~hasti/cs367-common/notes/COMPLEXITY.html#bigO

Should be:

http://pages.cs.wisc.edu/~hasti/cs367-common/notes/4.COMPLEXITY.html#bigO

page 337

First paragraph says:

"... and pushes the algorithms to into other classes ..."

Should be

"... and pushes the algorithms into other classes ..."

Reported by Dirk Loss

page 338

Typo, Third line from the bottom:

>>> walker = visit('/Users/tarek/Desktop', FileReader())

Should be:

>>> visit('/Users/tarek/Desktop', FileReader())

Reported by Dirk Loss

page 338

Error in the visit function :

>>> def visit(visited, visitor):
...     cls = visited.__class__.__name__
...     meth = 'visit_%s' % cls
...     method = getattr(visitor, meth, None)
...     if meth is None:
...         meth(visited)
... 

The last two lines should be

...     if method is not None:
...         method(visited)

Reported by Dirk Loss