tough-to-explain Python

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Wed Jul 8 02:09:19 EDT 2009


On Tue, 07 Jul 2009 20:04:46 +0000, kj wrote:

> I'm having a hard time coming up with a reasonable way to explain
> certain things to programming novices.

[...]


> Or consider this one:
> 
>>>> ham = [1, 2, 3, 4]
>>>> spam = (ham,)
>>>> spam
> ([1, 2, 3, 4],)
>>>> spam[0] is ham
> True
>>>> spam[0] += [5]
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> TypeError: 'tuple' object does not support item assignment
>>>> ham += [5]
>>>> spam
> ([1, 2, 3, 4, 5, 5],)
>>>> 
>>>> 
> What do you say to that?


That one surely is very straight forward. Just like the exception says, 
tuples don't support item assignment, so spam[0] += [5] is not allowed.

But just because you have put a list inside a tuple doesn't mean the list 
stops being a list -- you can still append to the list, which is what 
ham += [5] does. So spam is unchanged: it is still the one-item tuple 
containing a list. It is just that the list has now been modified.

This is only troublesome (in my opinion) if you imagine that tuples are 
somehow magical "frozen-lists", where the contents can't be modified once 
created. That's not the case -- the tuple itself can't be modified, but 
the objects inside it remain ordinary objects, and the mutable ones can 
be modified.

The thing to remember is that the tuple spam doesn't know anything about 
the *name* ham -- it knows the object referred to by the name ham. You 
can modify the name, and nothing happens to the tuple:

>>> spam
([1, 2, 3, 4, 5],)
>>> ham = [5]
>>> spam
([1, 2, 3, 4, 5],)

Or if you prefer:

>>> ham = spam[0]  # label the list inside spam as 'ham'
>>> ham += [6]  # modify the list labelled as 'ham'
>>> spam
([1, 2, 3, 4, 5, 6],)
>>> pork = ham  # create a new label, 'pork', and bind it to the same list
>>> del ham  # throw away the label 'ham'
>>> pork += [7]  # modify the list labelled as 'pork'
>>> spam
([1, 2, 3, 4, 5, 6, 7],)


It's all about the objects, not the names.



-- 
Steven



More information about the Python-list mailing list