Scripts explained

From
Edward Welbourne <eddy@opera.com>
To
peter@opera.com
Date
Wed, 17 Nov 2004 11:35:29 +0100
Subject
Re: encodings, python

[…discussion deleted…]

Feel free to ask questions ... Note that basetable.py contains
critical base classes and is relatively thoroughly documented.  Note
that Table.load() relies on thing[key] working equally well when
"thing" is a list of dictionary; the underlying semantics are subtly
different, but they're written identically (both for reading and
setting).  The twoDict class in tableutils.py is an object which
"behaves like" a dictionary or list for the same purposes.

I think I restrained myself from using anything too clever.  Ah, but I
see I've made extensive use of apply(), map() and reduce() - these are
functional programming idioms.  Hopefully not too hard to follow.

One ediosyncratic idiom I've used a fair bit (illustration from
tableutils):

class byteTable (textTable):
    __load = textTable.load
    def load(self, fwd=[]):
        return self.__load(fwd + [ NON_UNICODE ] * (256 - len(fwd)))

Where I'm over-riding a base-class's version of a method, I save that
version in the derived class's private namespace (any name beginning
but not ending __ is "private" to the class in whose body it appears;
in fact, uses of it in that class are mangled in a simple way) so that
instances can reference it easily, without having to go via the base
class (and be passed overtly as first argument).  Thus the call to
self.__load(...) is equivalent to textTable.load(self, ...)

Another (more orthodox) idiom I've used is for the last few
"parameters" in a function's definition to have "defaults" which are
meant to never be over-ridden; this is an idiom for saving a value
from the context in which the function was defined and making it
available to the function's body.  The value can then be forgotten by
the defining context; but the function still retains its reference to
it.  Thus, in tables.py, the variable table_class is first used for a
dictionary and later used for a function, which takes the dictionary
as "default" for its parameter "special" (which is used for the bulk
look-up in which the function ends).  Although defining the function
kicks the dictionary out of the module's name-space, the dictionary
object survives, referenced by the new function object's dictionary of
parameter defaults.  The function is then, itself, supplied as default
to the exported function table().  In each case, the prior value of
table_class (is technically a python object that) gets tied to a name
in the newly created function object's name-space; subsequent deletion
of the name (see end of the file) merely removes that name from the
module's name-space, it doesn't change the fact that the object
previously known by that name is still referenced by the function.
This trick makes it possible to avoid clutter in a module's namespace
(but I actually left lots of ...Table names in tables.py's namespace).
The table_class example is extreme; in both cases, I've likewise
provided string.find to the function in like manner - this is a more
usual usage, making for a local namespace look-up, which is cheaper
than a global one (to find string) followed by an attribute look-up
(on string, to get its .find).

In many cases, where I've used this, I've separated the value-tunnels
from the true parameters by putting them on a separate line.  Note
that, where basetable.py's textTable.digest()'s body over-rides the
value of find (when no comment delimiter is provided) this only
affects the call in which it happens; subsequent calls get the
original value of find.  (But note that if a parameter of this kind
has a mutable object as its value, e.g. a list val=[], changes to that
object, e.g. val.append(1), will still be visible to later calls to
the function; it's only assignments to the name that are forgotten -
val=val+[1] would have the same effect as val.append() for the call in
which it happens, but without affecting subsequent calls.)

I've checked in some doc fixes while typing this !

	Eddy.