3 ms·
>>> another_tuple ([1, 2], [3, 4], [5, 6, 1000]) >>> another_tuple[2] += [99, 999] TypeError: 'tuple' object does not support item assignment >>
by pansa2 6y ago
>>> another_tuple
([1, 2], [3, 4], [5, 6, 1000])
>>> another_tuple[2] += [99, 999]
TypeError: 'tuple' object does not support item assignment
>>> another_tuple
([1, 2], [3, 4], [5, 6, 1000, 99, 999])
This one's my favorite. Although it's a rare issue that you're unlikely to come across, it's a side-effect of a much bigger design flaw in Python - the decision to make `a += b` behave differently from `a = a + b`.
- maweki 6y agoIt's a design decision to allow it to behave differently, as you can implement += with a more efficient in-place version, instead of a copying one where the lvalue might be different/new and you have to keep the old a. I even think this is good design, as by convention + does not mutate its arguments but += can be a fast mutating version.
- pansa2 6y agoI guess reference counting makes copying a list in Python a much more expensive operation than it would be in other languages. Although perhaps it could also be used to avoid copying in cases where the list's own reference count is exactly 1? Anyway, there's nothing wrong with offering an operator to change a list in-place, but IMO `+=` is the wrong way to spell it.
- maweki 6y ago> but IMO `+=` is the wrong way to spell it. Again, operator overloading. __iadd__ just calls append. Many a library might do something much better. But as it looks like the in-place version of +, even for lists it seems fine (although I've been missing a concat-operator in python for years - seems we're stuck with +).
- yongjik 6y agoI'd say it's even deeper - the += operator is fundamentally tied with Python's semantics. Consider: >>> a = [1, 2] >>> b = a >>> a = a + [3] >>> b [1, 2] It has to be [1, 2] because the third line creates a new object. If a + operation changes its operand, then the concept of object identity breaks down - at least, it will be a very different language.
- pansa2 6y agoYou’re right - I’m not suggesting that `+` should work in-place, but that `a += b` should do the same thing as `a = a + b` and not work in-place.
- BerislavLopac 6y agoSo you're saying that a += b should create a new object and assign it to a? Now that would be even more unexpected...
- pansa2 6y agoI don’t think it’s unexpected for an augmented assignment operator to do an assignment. It is unexpected for it to instead call `extend`. It’s even worse to do the first for some types and the second for other types.
- kzrdude 6y agoThat's a wart and a half. It puzzles me to no end that this would be an error - `another_tuple[0].append(3)` is not an error.
- pansa2 6y agoIt’s because `another_tuple[2] += [99, 999]` is equivalent to something similar to `another_tuple[2] = another_tuple[2].__iadd__([99, 999])`. The list is modified in __iadd__ but then the assignment fails. The assignment is necessary in case __iadd__ doesn’t want to modify in-place and instead return a new value. It’s this “sometimes modify in-place, sometimes don’t” which causes the issue.