[Python-ideas] Wild idea about mutability

Steven D'Aprano steve at pearwood.info
Wed Jun 1 21:34:20 EDT 2016


On Wed, Jun 01, 2016 at 11:26:07PM +0100, Rob Cliffe wrote:
> I was prompted to post this after seeing comments on "Proposal to change 
> List Sequence Repetition (*) so it is not useless for Mutable Objects" 
> that you cannot in general tell whether an object is mutable or not.
> 
> Well, why shouldn't you be able to tell?  Python is superb at 
> introspection, but ISTM there's a gap here.  Here's an idea for Python N 
> (N>=4):  Every object has a boolean __mutable__ attribute.  It would 
> e.g. be False for ints and strings,  True by default for objects that 
> can be mutable, such as lists and dicts.

I hate to break it to you, but merely setting a flag on an object 
doesn't make it mutable or immutable *wink*

That means that every class (possibly including builtins) needs to be 
re-written so that every mutator method checks this flag and decides 
whether or not to allow the mutation. For example, you suggest:

"You don't need tuples.  You just have a list with __mutable__ = False."

Now the code for list append must be:

    def append(self, item):
        # only written in C, because its a built-in
        if self.__mutable__:
            ...
        else:
            raise SomeError

Now multiply that by *every* mutator class and method. This will be 
especially burdensome for people writing classes intended to be mutable, 
since they have to support immutability whether they want it or not.

(Since the caller might change obj.__mutable__ to False, which is 
allowed.)

This will break type-checking and duck-typing and make feature 
detection a pain:

# currently this works
if hasattr(obj, 'append'):
    handle_things_that_can_append(obj)
else:
    handle_things_that_cant_append(obj)

# with your scheme
if hasattr(obj, 'append'):
    if obj.__mutable__:
        handle_things_that_can_append(obj)
    else:
        handle_things_that_cant_append(obj)
else:
    handle_things_that_cant_append(obj)


> It could be an optional extra 
> argument to mutable object constructors (so you have the option of 
> making them immutable):
> 
>     L = list(somesequence, mutable=False)

This goes against the "no constant bool arguments" design guideline.


> There could also be a syntax for list/set literals and dictionary 
> displays to indicate that they should be immutable (just as we preface 
> literal strings with 'r' to indicate raw strings).  I'm not sure what; I 
> thought of f[1,2,3] for a literal immutable ("frozen") list, but that's 
> already valid syntax.

We already have syntax for a built-in immutable list-like sequence 
object (a "frozen list" if you will):

(1, 2, 3)


> You can "freeze" a mutable object by changing its __mutable__ attribute 
> from True to False.  You are not allowed to change it from False to 
> True, nor to mutate an object that has it False.
> 
> I am sure there must be advantages in being able to tell if an object is 
> mutable or not.  (Perhaps "hashable" equals "not mutable" ?)

No it does not.

(1, 2, [3]) is both immutable and unhashable.


> Now:  You don't need the frozenset class.  You just have a set with 
> __mutable__ = False.  And you can freeze dicts (classes? modules?) etc., 
> to make sure users of your code don't mess with them.

And we get this functionality for free, right? *wink*

Somebody has to write this code. I'm not sure they will appreciate 
having to throw away all the perfectly good frozenset code and tests, 
and re-writing set to handle both cases. Not to mention the breaking of 
backwards compatibility to get rid of frozenset.


> And (fasten your safety belts): You don't need tuples.  You just have a 
> list with __mutable__ = False.  And you don't have to explain to 
> beginners one of the most FAQ "Why do we need lists and tuples?"

(1) I don't remember ever seeing a beginner confused by this difference, 
but I see plenty of experienced programmers who are sure that they must 
be.

(2) Have you actually read the FAQ? Because if you have, you should 
realise that having an immutable list is not the same as having a tuple.

Tuples are intended for "record-like" structures, where the items' 
positions are meaningful, while lists are intended for "array-like" 
structures where all the items have the same type and their position is 
not meaningful. While it's not compulsory to treat tuples and lists 
this way, it is very useful to do so.



-- 
Steve


More information about the Python-ideas mailing list