John O'Hagan wrote: > I'm looking for good ways to ensure that attributes are only writable such > that they retain the characteristics the class requires.
That's what properties are for. > My particular case is a class attribute which is initialised as a list of > lists of two integers, the first of which is a modulo remainder. I need to > be able to write to it like a normal list, but want to ensure it is only > possible to do so without changing that format. Then you have two problems to solve. First, you need a special type of list that only holds exactly two integers. Your main class can't control what happens inside the list, so you need the list to validate itself. Secondly, you should use a property in your main class to ensure that the attribute you want to be a special list-of-two-ints can't (easily) be changed to something else. > Below is a what I eventually came up with; a container class called > OrderElement for the inner lists, and subclass of list called Order for > the main attribute, which is a property of the main class, simplified > below as SeqSim. It works, but seems like a hell of a lot of code for a > simple idea. And why should this be surprising? It might be a simple *idea*, but the concrete execution of that idea is anything but simple. "Hey, let's fly to Mars!" is a simple idea too. Nevertheless, it does appear that your solution below is overly complicated. Two helper classes just to have a thing that holds two ints... does it have to be a list? Seems that if you're limited to exactly two items, a list is pretty useless, since you can't insert, append, pop or delete items. I'd take this approach instead: # Untested. class ThingWithTwoIntegers(object): def __init__(self, a, b): self.a = a self.b = b def __getitem__(self, index): # Slicing not supported, because I'm lazy. if index < 0: index += 2 if index == 0: return self.a elif index == 1: return self.b else: raise IndexError def __setitem__(self, index, value): # Slicing not supported, because I'm lazy. if index < 0: index += 2 if index == 0: self.a = value elif index == 1: self.b = value else: raise IndexError def _geta(self): return self._a def _seta(self, value): if isinstance(value, (int, long)): # drop long if using Python 3 self._a = value else: raise TypeError('expected an int but got %s' % type(value)) a = property(_geta, _seta) # and the same for b: _getb, _setb, making the obvious changes There's a little bit of code duplication there, but it's 3am here and I'm tired and besides, if I do all your work what would you do? *wink* This gives you an object that holds two integers. You can access them either by attribute name, "a" and "b", or by index, 0 and 1: instance = ThingWithTwoIntegers(23, 42) instance[0] => 23 instance.b => 42 Obviously this isn't a full blown list, but if you don't need all the list-like behaviour (sorting, inserting, deleting items, etc.) why support it? -- Steven -- http://mail.python.org/mailman/listinfo/python-list