# 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.