Could you explain this rebinding (or some other action) on "nums = nums"?

MRAB python at mrabarnett.plus.com
Mon Nov 30 22:32:31 EST 2015


On 2015-12-01 02:14, fl wrote:
> On Wednesday, June 24, 2015 at 8:17:08 PM UTC-4, Chris Angelico wrote:
>> On Thu, Jun 25, 2015 at 9:52 AM, fl <rxjgmail.com> wrote:
>> > The reason is that list implements __iadd__ like this (except in C, not Python):
>> >
>> > class List:
>> >     def __iadd__(self, other):
>> >         self.extend(other)
>> >         return self
>> > When you execute "nums += more", you're getting the same effect as:
>> >
>> > nums = nums.__iadd__(more)
>> > which, because of the implementation of __iadd__, acts like this:
>> >
>> > nums.extend(more)
>> > nums = nums
>> > So there is a rebinding operation here, but first, there's a mutating operation, and the rebinding operation is a no-op.
>>
>> It's not a complete no-op, as can be demonstrated if you use something
>> other than a simple name:
>>
>> >>> tup = ("spam", [1, 2, 3], "ham")
>> >>> tup[1]
>> [1, 2, 3]
>> >>> tup[1].extend([4,5])
>> >>> tup[1] = tup[1]
>> Traceback (most recent call last):
>>   File "<stdin>", line 1, in <module>
>> TypeError: 'tuple' object does not support item assignment
>> >>> tup
>> ('spam', [1, 2, 3, 4, 5], 'ham')
>> >>> tup[1] += [6,7]
>> Traceback (most recent call last):
>>   File "<stdin>", line 1, in <module>
>> TypeError: 'tuple' object does not support item assignment
>> >>> tup
>> ('spam', [1, 2, 3, 4, 5, 6, 7], 'ham')
>>
>> The reason for the rebinding is that += can do two completely
>> different things: with mutable objects, like lists, it changes them in
>> place, but with immutables, it returns a new one:
>>
>> >>> msg = "Hello"
>> >>> msg += ", world!"
>> >>> msg
>> 'Hello, world!'
>>
>> This didn't change the string "Hello", because you can't do that.
>> Instead, it rebound msg to "Hello, world!". For consistency, the +=
>> operator will *always* rebind, but in situations where that's not
>> necessary, it rebinds to the exact same object.
>>
>> Does that answer the question?
>>
>> ChrisA
>
> I have revisit the past post. In the example code snippet:
>
> type(tup[1])
> Out[162]: list
>
> 'list' is mutable. Why does the following line have errors?
> In practical Python code, error is not acceptable. Then, what purpose is
> for the following code here to show?
>
> Thanks,
>
>
>>>> tup[1] += [6,7]
> Traceback (most recent call last):
>    File "<stdin>", line 1, in <module>
> TypeError: 'tuple' object does not support item assignment
>
When you write:

     x += y

Python tries to do:

     x = x.__iadd__(y)

If x doesn't have the "__iadd__" method, Python then tries to do:

     x = x.__add__(y)

The "__iadd__" method should mutate the object in-place and then return
itself.

Here's an example where it returns something else instead:

# Example

class Test:
     def __init__(self):
         self.string = ''

     def __iadd__(self, other):
         self.string += other
         return "Surprise!"

t = Test()
t += 'foo'
print(t)

# End of example

In the case of:

     tup[1] += [6, 7]

what it's trying to do is:

     tup[1] = tup[1].__iadd__([6, 7])

tup[1] refers to a list, and the __iadd__ method _does_ mutate it, but
then Python tries to put the result that the method returns into
tup[1]. That fails because tup itself is a tuple, which is immutable.




More information about the Python-list mailing list