Larry Hastings wrote:
I knocked together a quick prototype of a "record" to show what I had
in mind. Here goes:
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 &
positional | list tuple
keyword | dict record
__classname__ = "record"
s = [self.__classname__, "("]
comma = ""
for name in self.__names__:
s += (comma, name, "=", repr(self[name]))
comma = ", "
s += ")"
def __delitem__(self, name):
raise exceptions.TypeError("object is read-only")
def __setitem__(self, name, value):
def __getattr__(self, name):
if name in self:
return object.__getattr__(self, name)
def __hasattr__(self, name):
if name in self.__names__:
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)
# a shortcut to throw our exception
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")
# 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")
p = Point(3, 5)
q = Point(2, y=5)
r = Point(y=2, x=4)
print p, q, r
# test pickling
pikl = pickle.dumps(p)
pp = pickle.loads(pikl)
print pp == p
# test that the output repr works to construct
s = repr(p)
peval = eval(s)
print p == peval
Yeah, I considered using __slots__, but that was gonna take too long.