You Can’t Change Me

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[1] 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

[1] But for which I have no reference I can find at the moment…

One thought on “You Can’t Change Me

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s