
On Feb 13, 2015, at 16:51, Rob Cliffe <rob.cliffe@btinternet.com> wrote:
On 13/02/2015 06:19, Steven D'Aprano wrote:
On Thu, Feb 12, 2015 at 07:43:36PM -0800, Chris Barker - NOAA Federal wrote:
avoids any confusion over operators and having += duplicating the update method. += duplicates the extend method on lists. Yes it does, and that sometimes causes confusion when people wonder why alist += blist is not *quite* the same as alist = alist + blist. It also leads to a quite ugly and unfortunate language wart with tuples:
py> t = ([], None) py> t[0] += [1] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment py> t ([1], None)
Try explaining to novices why this is not a bug. Er, I'm not a novice, but why isn't that a bug? I would have expected t to be altered as shown without raising an exception. (And given that the code does raise an exception, I find it surprising that it otherwise has the presumably intended effect.) t[0] is a list, not a tuple, so I would expect it to behave as a list:
Right, t[0] behaves like a list. But assigning (augmented or otherwise) to t[0] isn't an operation on the value t[0], it's an operation on the value t (in particular, `t.__setitem__(0, newval)`). Augmented assignment does three things: it fetches the existing value, calls the __iadd__ operator on it (or __add__ if there's no __iadd__, which is how it works for immutable values), then stores the resulting new value. For this case, the first two steps succeed, and the third fails. There's really no good alternative here. Either you don't allow augmented assignment, you don't allow it to work with immutable values (so `t=[0]; t[0] += 1` fails), or you add reference types and overloadable assignment operators and the whole mess that comes with them (as seen in C++) instead of Python's nifty complex assignment targets.
L = t[0] L += [2] t ([1,2], None)
I was also curious why you say that alist += blist is not quite the same as alist = alist + blist. (So far I've worked out that the first uses __iadd__ and the second uses __add__. And there is probably a performance difference. And the semantics could be different for objects of a custom class, but as far as I can see they should be the same for list objects. What have I missed?)
Consider this case: >>> clist = [0] >>> alist = clist >>> blist = [1] Now, compare: >>> alist = alist + blist >>> clist [0] ... versus: >>> alist += blist >>> clist [0, 1] And that's because the semantics _are_ different for __add__ vs. __iadd__ for a list: the former creates and returns a new list, the latter modifies and returns self, and that's clearly visible (and often important to your code!) if there are any other references to self out there. That's the real reason we need __iadd__, not efficiency.
I would appreciate it if you or someone else can find the time to answer. Rob Cliffe
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/