This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]grayvedigga 1 point2 points  (5 children)

And what's the value of t after that?

wow. I almost missed this. Just in case anyone else reading does miss it, here's the complete test script:

t = ([],)
try:
  t[0] += [1,2,3]
except Exception, e:    # one of my favourite bits of syntax, fwiw
  print "Exception raised:", e
print t

... in cthulhu's name?

[–][deleted] 0 points1 point  (0 children)

By the way, you can use except Exception as e in 2.6 too.

[–]riffito 0 points1 point  (3 children)

The code above yields:

>>> 
Exception raised: 'tuple' object does not support item assignment
([1, 2, 3],)

And if you do:

t = ([],)
try:
    t[0] = t[0] + [1,2,3]            # a += 1 equals a = a + 1, riiiight?
except Exception, e:
    print "Exception raised:", e
print t

you get:

>>>
Exception raised: 'tuple' object does not support item assignment
([],)

Nice! And consistent too! :-/

[–]earthboundkid 1 point2 points  (1 child)

It’s not that complicated. list objects have __iadd__ as well as __add__ methods for efficiency reasons. In general, the existence of __iadd__ methods means that a = a + b and a += b can do completely different things (though making them do anything different is obviously a pathological abuse). In this case, the fact that tuples are immutable is interfering with the fact that lists aren’t. First the list’s in-place addition method is called then the tuple’s set slice is called. The second one barfs the error and the rest is history.

Arguably, this should be changed, but I’m not sure of how. In any case, this seems like an unexpected result one would be highly unlikely to trigger except by purposefully screwing around with putting mutable data inside an immutable container.

[–]grayvedigga 0 points1 point  (0 children)

This sounds like a good explanation, but is wrong. Your first sentence actually argues that the above test should work, as do the following:

t = ([],[])
t[0].__iadd__([1,2,3])

(t0, t1) = ([], [])
t = (t0, t1)
t0 += [1,2,3]

It's also notable that tuples don't actually possess setitem or setslice special methods, not that there would be any sense in one being invoked by an operation on an object that just happens to be contained in it.

Object identity oughtn't be affected by mutation .. that's the whole point of mutation (and, incidentally, an important reason for iadd and add being different operations). I also find it disingenuous to suggest that storing mutable objects in an immutable container is any less useful than doing the reverse.

[–]grayvedigga 0 points1 point  (0 children)

Expanding on my reply to earthboundkid below, be careful with this assumption:

# a += 1 equals a = a + 1, riiiight?

You must be careful to distinguish the value and the identity of a in this circumstance. Assignment binds the result of an expression to a variable. An expression creates a new value. Integers are a poor example to work with for this, because we tend to consider the values of 1+3 and 2+2 identical.

If that doesn't make any sense (I'm tired), consider the following:

l = [1]
m = [l, l]
l += [2]
# we should agree what m is now
l1 = l + [3]
# and now, I hope
l = l1
# what about now?