Steven D'Aprano <steve+comp.lang.pyt...@pearwood.info> writes: > Perhaps you are thinking that Python could determine ahead of time > whether x[1] += y involved a list or a tuple, and not perform the > finally assignment if x was a tuple. Well, maybe, but such an approach > (if possible!) is fraught with danger and mysterious errors even > harder to debug than the current situation. And besides, what should > Python do about non-built-in types? There is no way in general to > predict whether x[1] = something will succeed except to actually try > it.
An alternative approach is to simply not perform the final assignment if the in-place method is available on the contained object. No prediction is needed to do it, because the contained object has to be examined anyway. No prediction is needed, just don't. Currently, lhs[ind] += rhs is implemented like this: item = lhs[ind] if hasattr(item, '__iadd__'): lhs.__setitem__(ind, item.__iadd__(rhs)) else: lhs.__setitem__(ind, item + rhs) # (Note item assignment in both "if" branches.) It could, however, be implemented like this: item = lhs[ind] if hasattr(item, '__iadd__'): item += rhs # no assignment, item supports in-place change else: lhs.__setitem__(ind, lhs[ind] + rhs) This would raise the exact same exception in the tuple case, but without executing the in-place assignment. On the other hand, some_list[ind] += 1 would continue working exactly the same as it does now. In the same vein, in-place methods should not have a return value (i.e. they should return None), as per Python convention that functions called for side effect don't return values. The alternative behavior is unfortunately not backward-compatible (it ignores the return value of augmented methods), so I'm not seriously proposing it, but I believe it would have been a better implementation of augmented assignments than the current one. The present interface doesn't just bite those who try to use augmented assignment on tuples holding mutable objects, but also those who do the same with read-only properties, which is even more reasonable. For example, obj.list_attr being a list, one would expect that obj.list_attr += [1, 2, 3] does the same thing as obj.list_attr.extend([1, 2, 3]). And it almost does, except it also follows up with an assignment after the list has already been changed, and the assignment to a read-only property raises an exception. Refusing to modify the list would have been fine, modifying it without raising an exception (as described above) would have been better, but modifying it and *then* raising an exception is a surprise that takes some getting used to. -- http://mail.python.org/mailman/listinfo/python-list