Although I have never needed this, it just struck me that making an immutable object in Python could be slightly tricky. You can't just override __setattr__
, because then you can't even set attributes in the __init__
. Subclassing a tuple is a trick that works:
class Immutable(tuple):
def __new__(cls, a, b):
return tuple.__new__(cls, (a, b))
@property
def a(self):
return self[0]
@property
def b(self):
return self[1]
def __str__(self):
return "<Immutable {0}, {1}>".format(self.a, self.b)
def __setattr__(self, *ignored):
raise NotImplementedError
def __delattr__(self, *ignored):
raise NotImplementedError
But then you have access to the a
and b
variables through self[0]
and self[1]
, which is annoying.
Is this possible in Pure Python? If not, how would I do it with a C extension?
(Answers that work only in Python 3 are acceptable).
Update:
So subclassing tuple is the way to do it in Pure Python, which works well except for the additional possibility of accessing the data by [0]
, [1]
etc. So, to complete this question all that is missing is howto do it "properly" in C, which I suspect would be quite simple, by just not implementing any geititem
or setattribute
, etc. But instead of doing it myself, I offer a bounty for that, because I'm lazy. :)
Yet another solution I just thought of: The simplest way to get the same behaviour as your original code is
Immutable = collections.namedtuple("Immutable", ["a", "b"])
It does not solve the problem that attributes can be accessed via [0]
etc., but at least it's considerably shorter and provides the additional advantage of being compatible with pickle
and copy
.
namedtuple
creates a type similar to what I described in this answer, i.e. derived from tuple
and using __slots__
. It is available in Python 2.6 or above.