Hi James and Bob

> > The only thing I don't quite understand is how sp_table is used
> > without triggering an error "UnboundLocalError: local variable
> > 'sp_table' referenced before assignment", but it works.
> Don't understand this either. Sure looks like you are referencing it
> before assigning it.
> There seems to be some sort of python magic happening in client.py with
> the self.sp.find(p_type).
> Don't understand how the object address is known when you invoke sp.find().

I hope this helps:

    1. Python processes __init__.py first.
    2. Line 2724: sp_table is initialized as global to __init__.py
    3. Lines 2739–53: ServerPacket.__new__ is called to create class type SP 
    4.     Line 2728:    The SP class type is actually created
    5.     Line 2731–33: An instance of class SP is added to global sp_table
    6.     Line 2735:    That instance is aliased as the global variable sp
    7. Lines 2756+: Subclass types SP_* are likewise created
    8. Line 5105: Client class is instantiated, passing SP instance alias sp
    9. Line 2748: When Client nt calls self.sp.find, the packet type number
                  is looked up in global sp_table and the corresponding
                  tuple ( size, instance ) is returned.

There does not actually seem to be any reason for find to be a class member; Client only needs the function.  It looks as though it might be simpler for sp_table to be collections.defaultdict( lambda: ( None, None ) ) which is passed to Client instead of sp.