Larry Hastings wrote:
I'd prefer a lightweight frozen dict, let's call it a "record" 
after one of the suggestions in this thread.  That achieves symmetry:
                     mutable &     immutable &
                     heavyweight   lightweight
                   +--------------------------
        positional | list          tuple
        keyword    | dict          record
  
I knocked together a quick prototype of a "record" to show what I had in mind.   Here goes:

------
import exceptions

class record(dict):
    __classname__ = "record"
    def __repr__(self):
        s = [self.__classname__, "("]
        comma = ""
        for name in self.__names__:
            s += (comma, name, "=", repr(self[name]))
            comma = ", "
        s += ")"
        return "".join(s)

    def __delitem__(self, name):
        raise exceptions.TypeError("object is read-only")

    def __setitem__(self, name, value):
        self.__delitem__(name)

    def __getattr__(self, name):
        if name in self:
            return self[name]
        return object.__getattr__(self, name)

    def __hasattr__(self, name):
        if name in self.__names__:
            return self[name]
        return object.__hasattr__(self, name)

    def __setattr__(self, name, value):
        # hack: allow setting __classname__ and __names__
        if name in ("__classname__", "__names__"):
            super(record, self).__setattr__(name, value)
        else:
            # a shortcut to throw our exception
            self.__delitem__(name)

    def __init__(self, **args):
        names = []
        for name, value in args.iteritems():
            names += name
            super(record, self).__setitem__(name, value)
        self.__names__ = tuple(names)

if __name__ == "__main__":
    r = record(a=1, b=2, c="3")
    print r
    print r.a
    print r.b
    print r.c
   
    # this throws a TypeError
    # r.c = 123
    # r.d = 456
   
    # the easy way to define a "subclass" of record
    def Point(x, y):
        return record(x = x, y = y)
   
    # you can use hack-y features to make your "subclasses" more swell
    def Point(x, y):
        x = record(x = x, y = y)
        # a hack to print the name "Point" instead of "record"
        x.__classname__ = "Point"
        # a hack to impose an ordering on the repr() display
        x.__names__ = ("x", "y")
        return x
   
    p = Point(3, 5)
    q = Point(2, y=5)
    r = Point(y=2, x=4)
    print p, q, r
   
    # test pickling
    import pickle
    pikl = pickle.dumps(p)
    pp = pickle.loads(pikl)
    print pp
    print pp == p
   
    # test that the output repr works to construct
    s = repr(p)
    print repr(s)
    peval = eval(s)
    print peval
    print p == peval
------

Yeah, I considered using __slots__, but that was gonna take too long.

Cheers,


larry