Immutability and Python

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Oct 29 19:02:38 EDT 2012


On Mon, 29 Oct 2012 15:20:02 +0000, andrea crotti wrote:

> I have a philosofical doubt about immutability, that arised while doing
> the SCALA functional programming course.

"Philosophical". Like most words derived from the ancient Greeks, the "F" 
sound uses "ph" rather than "f".


> Now suppose I have a simple NumWrapper class, that very stupidly does:
> 
> class NumWrapper(object):
>     def __init__(self, number):
>         self.number = number
> 
> and we want to change its state incrementing the number, normally I
> would do this
> 
>     def increment(self):
>         self.number += 1

That's a perfectly fine (although incomplete) design for a mutable 
numeric class. But as the basis of an immutable class, it's lousy.

> But the immutability purists would instead suggest to do this:
> 
>     def increment(self):
>         return NumWrapper(self.number + 1)

Only if they don't know Python very well :-)

In this example, the right way to get an immutable class is:

class NumWrapper(int):  # not exactly a *wrapper*
    def increment(self):
        return self.__class__(self + 1)


and you're done. Immutability for free, because you don't store state 
anywhere that pure-Python code can get to it. (Technically, using ctypes 
you could mutate it, so don't do that.)

Here's a sketch of another technique:

class MyNum(object):
    __slots__ = '_num'
    def __new__(cls, arg):
        instance = object.__new__(cls)
        instance._num = int(arg)
        return instance
    @property
    def value(self):
        return self._num
    def increment(self):
        return self.__class__(self.value + 1)


> Now on one hand I would love to use only immutable data in my code, but
> on the other hand I wonder if it makes so much sense in Python.

You can go a long, long way using only immutable primitives and 
functional style in Python, and I recommend it.

On the other hand, a *purely* functional approach doesn't make a lot of 
sense for some tasks. Python is not a pure functional language, and 
doesn't force you to hammer round pegs into the square hole of the 
functional style.

Some problems are best modelled by an object that holds state and can 
change over time, e.g. a database or a dict. Other problems are best 
modelled by constants which do not change, but can be replaced by other 
constants, e.g. numbers. Some problems fall into a grey area, e.g. lists, 
arrays, sets, sequences, strings.

My advice is to always be alert for square pegs in your code, and write 
them in functional style using immutable instances, but don't be a 
purist. If you have a round peg, write that part of your code using a 
mutable instance with in-place mutator methods, and be happy.

The beauty of Python is that you can use whichever style suits the 
problem best.


> My impression is that things get more clumsy in the immutable form, for
> example in the mutable form I would do simply this:
> 
> number = NumWrapper(1)
> number.increment()
> 
> while with immutability I have to do this instead: 
> new_number = number.increment()

Why is this clumsy? Do you have problems with this?

x = 1
y = x+1



-- 
Steven



More information about the Python-list mailing list