Mutability is interesting. A while ago, someone pointed me to these discussions of the essential differences between tuples and lists. Guido’s quote: Tuples are for heterogeneous data, list are for homogeneous data. Tuples are *not* read-only lists. On the other hand, one can find plenty of Python references such as this which includes the statement “A tuple is an immutable ordered list of objects”. Ditto this from DiveIntoPython; “A tuple is an immutable list”. Does “list” in that sentence mean the list type, or the list concept? Perhaps it depends on your point of view, and how much you revere Guido 🙂
Anyway, a general Van Rossum principle that I tend to like is that where a function returns an object as a result, that object should be immutable. Obviously, like all sweeping generalisations, this is demonstrably wrong in various circumstances, but it’s a useful rule of thumb when pondering architectures. Thus I find mutability interesting.
What I’d really like to find is an elegant way to product a list subclass that could be made immutable easily (and doing tuple(myList) is cheating). The most interesting approach would be a class that proxied around an object that starts as a list but then converts that to a tuple when set immutable. Perhaps overriding __getattr__ and catching calls for __methods__ might help… but then there’s the risk of someone being clever and saving a reference to a bound method object. More on this, I fear, later.
Meanwhile, here’s a snippet of my playing around; a class that uses the inspect module to do a clever thing; it will only allow its attributes to be set by code defined in the same module as the class itself:
#File semimutable.py #Note that this module imports itself import inspect, semimutable class AssignmentError(TypeError): pass class SelfMutable(object): """An object whose values can only be changed by its own methods.""" def __setattr__(self, attr, value): #get code object of caller c = inspect.currentframe(1).f_code if not inspect.getmodule(c) == semimutable: raise AssignmentError, "object is immutable" object.__setattr__(self, attr, value) def setTest(self, value): self.test = value
And here’s a little test script that demonstrates it (you’d need to put this in some other module or run it interactively).
import semimutable d = semimutable.SelfMutable() d.setTest(2) print "test is %d" % d.test d.test = 1
It gives the output:
test is 2 Traceback (most recent call last): File "C:\Python23\Lib\site-packages\pythonwin\pywin\framework\scriptutils.py", line 310, in RunScript exec codeObject in __main__.__dict__ File "C:\Documents and Settings\ben\My Documents\ben\python\mutabilitytest.py", line 8, in ? File "semimutable.py", line 83, in __setattr__ raise AssignmentError, "object is immutable" AssignmentError: object is immutable
 But for which I have no reference I can find at the moment…