a question about list as an element in a tuple

rusi rustompmody at gmail.com
Sun Dec 15 23:12:25 EST 2013


On Monday, December 16, 2013 9:27:11 AM UTC+5:30, Chris Angelico wrote:
> On Mon, Dec 16, 2013 at 2:30 PM, liuerfire Wang  wrote:
> > TypeError: 'tuple' object does not support item assignment
> > In [5]: a
> > Out[5]: ([1, 1], [])
> > no problem, there is an exception. But a is still changed.
> > is this a bug, or could anyone explain it?

> It's not a bug, but it's a bit confusing. Here's what happens. The
> augmented assignment operator += triggers an in-place addition (where
> possible; for lists, it's possible), so the original list will be
> changed:

> >>> a = [1]
> >>> b = a
> >>> a += [2]
> >>> b
> [1, 2]

> Whereas using separate assignment and addition creates a new list:

> >>> a = a + [3]
> >>> a
> [1, 2, 3]
> >>> b
> [1, 2]

> To handle both mutable types (like list) and immutable ones (like
> str), the augmented assignment operators have to be able to choose
> whether or not they change their object:

> >>> a = "1"
> >>> b = a
> >>> a += "2"
> >>> b
> '1'
> >>> a
> '12'

> So what happens under the hood is, more or less:

> a += [2]
> # ... is equivalent to ...
> a = a.__iadd__([2])

> Which can be explored interactively:

> >>> a = [1]
> >>> a.__iadd__([2])
> [1, 2]
> >>> a
> [1, 2]

> The __iadd__ function ("in-place add") returns the new result, and in
> the case of the list, that's done by changing the list. The assignment
> is then done, which does nothing here, but with strings, is the
> critical part of the job. So far, so good.

> Now, when that result gets assigned to the tuple, we have a problem.
> Tuples are immutable - can't change length (no appending), and can't
> assign to elements. So when the final step happens, an exception is
> thrown. At that point, the tuple is complaining "Hey, you can't assign
> to me!", but the list has already done the appending, and it's too
> late to undo that. So the list has changed, and when you go look at
> it, you see the change (since the list is the same whether you find it
> from the tuple or somewhere else), which creates the confusing
> situation of throwing an exception after doing exactly what you
> wanted.

> Python exceptions aren't like SQL errors, causing a rollback of the
> whole transaction. Or, more generally, Python expressions and
> statements aren't transactional. So it's entirely possible, if a
> little confusing, for part of a job to happen. Let's take another
> example that has side effects:

> tup = (1,2,3)
> tup[2] = input("Enter something: ")   # use raw_input() in Python 2

> Tuple assignment can't work... but it's fairly clear that this
> _should_ still show the prompt and wait for the user to type
> something, and only throw the exception later on. It's not as obvious
> in the augmented assignment example, but both are actually doing the
> same thing.

> Hope that helps!

Heh!
Nice question... even nicer explanation!!

I thought I knew that imperative programming is a bad idea:
http://blog.languager.org/2012/11/imperative-programming-lessons-not.html

Never cease to be surprised how bad an idea it is!



More information about the Python-list mailing list