Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #99764 > unrolled thread
| Started by | fl <rxjwg98@gmail.com> |
|---|---|
| First post | 2015-11-30 18:14 -0800 |
| Last post | 2015-12-01 17:37 -0500 |
| Articles | 10 — 6 participants |
Back to article view | Back to comp.lang.python
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: Could you explain this rebinding (or some other action) on "nums = nums"? fl <rxjwg98@gmail.com> - 2015-11-30 18:14 -0800
Re: Could you explain this rebinding (or some other action) on "nums = nums"? MRAB <python@mrabarnett.plus.com> - 2015-12-01 03:32 +0000
Re: Could you explain this rebinding (or some other action) on "nums = nums"? Denis McMahon <denismfmcmahon@gmail.com> - 2015-12-01 20:32 +0000
Re: Could you explain this rebinding (or some other action) on "nums = nums"? Ian Kelly <ian.g.kelly@gmail.com> - 2015-12-01 14:44 -0600
Re: Could you explain this rebinding (or some other action) on "nums = nums"? Denis McMahon <denismfmcmahon@gmail.com> - 2015-12-01 21:37 +0000
Re: Could you explain this rebinding (or some other action) on "nums = nums"? Erik <python@lucidity.plus.com> - 2015-12-01 22:34 +0000
Re: Could you explain this rebinding (or some other action) on "nums = nums"? Erik <python@lucidity.plus.com> - 2015-12-01 22:44 +0000
Re: Could you explain this rebinding (or some other action) on "nums = nums"? Terry Reedy <tjreedy@udel.edu> - 2015-12-01 16:18 -0500
Re: Could you explain this rebinding (or some other action) on "nums = nums"? Denis McMahon <denismfmcmahon@gmail.com> - 2015-12-01 21:36 +0000
Re: Could you explain this rebinding (or some other action) on "nums = nums"? Terry Reedy <tjreedy@udel.edu> - 2015-12-01 17:37 -0500
| From | fl <rxjwg98@gmail.com> |
|---|---|
| Date | 2015-11-30 18:14 -0800 |
| Subject | Re: Could you explain this rebinding (or some other action) on "nums = nums"? |
| Message-ID | <b48d4b38-a28a-4408-8271-f79e850f453f@googlegroups.com> |
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
[toc] | [next] | [standalone]
| From | MRAB <python@mrabarnett.plus.com> |
|---|---|
| Date | 2015-12-01 03:32 +0000 |
| Message-ID | <mailman.51.1448940760.14615.python-list@python.org> |
| In reply to | #99764 |
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.
[toc] | [prev] | [next] | [standalone]
| From | Denis McMahon <denismfmcmahon@gmail.com> |
|---|---|
| Date | 2015-12-01 20:32 +0000 |
| Message-ID | <n3l050$l7a$4@dont-email.me> |
| In reply to | #99765 |
On Tue, 01 Dec 2015 03:32:31 +0000, MRAB wrote: > 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. I think I might have found a bug: $ python Python 2.7.3 (default, Jun 22 2015, 19:33:41) [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> tup = [1,2,3],[4,5,6] >>> tup ([1, 2, 3], [4, 5, 6]) >>> tup[1] [4, 5, 6] >>> tup[1] += [7,8,9] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment >>> tup[1] [4, 5, 6, 7, 8, 9] >>> tup ([1, 2, 3], [4, 5, 6, 7, 8, 9]) >>> quit() -- Denis McMahon, denismfmcmahon@gmail.com
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2015-12-01 14:44 -0600 |
| Message-ID | <mailman.83.1449002726.14615.python-list@python.org> |
| In reply to | #99815 |
On Tue, Dec 1, 2015 at 2:32 PM, Denis McMahon <denismfmcmahon@gmail.com> wrote: > On Tue, 01 Dec 2015 03:32:31 +0000, MRAB wrote: > >> 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. > > I think I might have found a bug: > > $ python > Python 2.7.3 (default, Jun 22 2015, 19:33:41) > [GCC 4.6.3] on linux2 > Type "help", "copyright", "credits" or "license" for more information. >>>> tup = [1,2,3],[4,5,6] >>>> tup > ([1, 2, 3], [4, 5, 6]) >>>> tup[1] > [4, 5, 6] >>>> tup[1] += [7,8,9] > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > TypeError: 'tuple' object does not support item assignment >>>> tup[1] > [4, 5, 6, 7, 8, 9] >>>> tup > ([1, 2, 3], [4, 5, 6, 7, 8, 9]) >>>> quit() No, that's the expected result. As MRAB wrote, the list *is* mutated when its __iadd__ method is called. The TypeError happens afterward when the assignment is attempted.
[toc] | [prev] | [next] | [standalone]
| From | Denis McMahon <denismfmcmahon@gmail.com> |
|---|---|
| Date | 2015-12-01 21:37 +0000 |
| Message-ID | <n3l3vk$l7a$6@dont-email.me> |
| In reply to | #99816 |
On Tue, 01 Dec 2015 14:44:38 -0600, Ian Kelly wrote: > On Tue, Dec 1, 2015 at 2:32 PM, Denis McMahon <denismfmcmahon@gmail.com> > wrote: >> On Tue, 01 Dec 2015 03:32:31 +0000, MRAB wrote: >> >>> 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. >> >> I think I might have found a bug: >> >> $ python Python 2.7.3 (default, Jun 22 2015, 19:33:41) >> [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" >> for more information. >>>>> tup = [1,2,3],[4,5,6] >>>>> tup >> ([1, 2, 3], [4, 5, 6]) >>>>> tup[1] >> [4, 5, 6] >>>>> tup[1] += [7,8,9] >> Traceback (most recent call last): >> File "<stdin>", line 1, in <module> >> TypeError: 'tuple' object does not support item assignment >>>>> tup[1] >> [4, 5, 6, 7, 8, 9] >>>>> tup >> ([1, 2, 3], [4, 5, 6, 7, 8, 9]) >>>>> quit() > > No, that's the expected result. As MRAB wrote, the list *is* mutated > when its __iadd__ method is called. The TypeError happens afterward when > the assignment is attempted. The assignment succeeds. That's imo a bug. If it's a TypeError to try and assign a value to tup[1], then tup[1] should not allow the mutated list to be assigned. -- Denis McMahon, denismfmcmahon@gmail.com
[toc] | [prev] | [next] | [standalone]
| From | Erik <python@lucidity.plus.com> |
|---|---|
| Date | 2015-12-01 22:34 +0000 |
| Message-ID | <mailman.88.1449009296.14615.python-list@python.org> |
| In reply to | #99821 |
On 01/12/15 21:37, Denis McMahon wrote: > The assignment succeeds. That's imo a bug. If it's a TypeError to try and > assign a value to tup[1], then tup[1] should not allow the mutated list > to be assigned. Nothing got assigned. That original list object remains in that slot. However, it has been mutated since it was originally assigned. But I can see what you're getting at - what you're asking for is that the *container* object whose element is being assigned to is first queried as to whether it will accept a mutated element being assigned to it before that element is mutated. This looks to be a fundamental issue with the augmented assignment mechanism. E.
[toc] | [prev] | [next] | [standalone]
| From | Erik <python@lucidity.plus.com> |
|---|---|
| Date | 2015-12-01 22:44 +0000 |
| Message-ID | <mailman.91.1449009930.14615.python-list@python.org> |
| In reply to | #99821 |
Apologies for self-replying, On 01/12/15 22:34, Erik wrote: > what you're asking for is that > the *container* object whose element is being assigned to is first > queried as to whether it will accept a mutated element being assigned to > it before that element is mutated. What I said above is rubbish. The situation is approximately similar to: a = [4, 5, 6] t = ([1, 2, 4], a) a.append(7) a.append(8) a.append(9) The point is, you're mutating something that an immutable object contains. In the example you give, that's caught because of the subsequent explicit assignment. In the example above, it's not caught. But it's the same thing. E.
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2015-12-01 16:18 -0500 |
| Message-ID | <mailman.84.1449004772.14615.python-list@python.org> |
| In reply to | #99815 |
On 12/1/2015 3:32 PM, Denis McMahon wrote: > On Tue, 01 Dec 2015 03:32:31 +0000, MRAB wrote: > >> 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. > > I think I might have found a bug: What you found is an specific example of what MRAB said in general above. > $ python > Python 2.7.3 (default, Jun 22 2015, 19:33:41) > [GCC 4.6.3] on linux2 > Type "help", "copyright", "credits" or "license" for more information. >>>> tup = [1,2,3],[4,5,6] >>>> tup > ([1, 2, 3], [4, 5, 6]) >>>> tup[1] > [4, 5, 6] >>>> tup[1] += [7,8,9] > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > TypeError: 'tuple' object does not support item assignment The bug is trying to replace a member of a tuple. The correct code, to avoid the exception while extending the list, is tup[1].extend([7,8,9]) >>>> tup[1] > [4, 5, 6, 7, 8, 9] -- Terry Jan Reedy
[toc] | [prev] | [next] | [standalone]
| From | Denis McMahon <denismfmcmahon@gmail.com> |
|---|---|
| Date | 2015-12-01 21:36 +0000 |
| Message-ID | <n3l3si$l7a$5@dont-email.me> |
| In reply to | #99818 |
On Tue, 01 Dec 2015 16:18:49 -0500, Terry Reedy wrote: > On 12/1/2015 3:32 PM, Denis McMahon wrote: >> On Tue, 01 Dec 2015 03:32:31 +0000, MRAB wrote: >> >>> 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. >> >> I think I might have found a bug: > > What you found is an specific example of what MRAB said in general > above. > >> $ python Python 2.7.3 (default, Jun 22 2015, 19:33:41) >> [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" >> for more information. >>>>> tup = [1,2,3],[4,5,6] >>>>> tup >> ([1, 2, 3], [4, 5, 6]) >>>>> tup[1] >> [4, 5, 6] >>>>> tup[1] += [7,8,9] >> Traceback (most recent call last): >> File "<stdin>", line 1, in <module> >> TypeError: 'tuple' object does not support item assignment > > The bug is trying to replace a member of a tuple. The correct code, to > avoid the exception while extending the list, is > > tup[1].extend([7,8,9]) > >>>>> tup[1] >> [4, 5, 6, 7, 8, 9] You snipped the important bit of my original post, which was the state of tup after the TypeError occurred. After the error, >>> tup[1] [4, 5, 6, 7, 8, 9] >>> tup ([1, 2, 3], [4, 5, 6, 7, 8, 9]) The "bug" I refer to is that despite giving the TypeError, the tuple allowed the assignment of the mutated list to replace the original list. -- Denis McMahon, denismfmcmahon@gmail.com
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2015-12-01 17:37 -0500 |
| Message-ID | <mailman.89.1449009497.14615.python-list@python.org> |
| In reply to | #99820 |
On 12/1/2015 4:36 PM, Denis McMahon wrote:
> On Tue, 01 Dec 2015 16:18:49 -0500, Terry Reedy wrote:
>
>> On 12/1/2015 3:32 PM, Denis McMahon wrote:
>>> On Tue, 01 Dec 2015 03:32:31 +0000, MRAB wrote:
>>>
>>>> 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.
>>>
>>> I think I might have found a bug:
>>
>> What you found is an specific example of what MRAB said in general
>> above.
>>
>>> $ python Python 2.7.3 (default, Jun 22 2015, 19:33:41)
>>> [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license"
>>> for more information.
>>>>>> tup = [1,2,3],[4,5,6]
>>>>>> tup
>>> ([1, 2, 3], [4, 5, 6])
>>>>>> tup[1]
>>> [4, 5, 6]
>>>>>> tup[1] += [7,8,9]
>>> Traceback (most recent call last):
>>> File "<stdin>", line 1, in <module>
>>> TypeError: 'tuple' object does not support item assignment
>>
>> The bug is trying to replace a member of a tuple. The correct code, to
>> avoid the exception while extending the list, is
>>
>> tup[1].extend([7,8,9])
>>
>>>>>> tup[1]
>>> [4, 5, 6, 7, 8, 9]
>
> You snipped the important bit of my original post, which was the state of
> tup after the TypeError occurred.
No I did not. The change to tup[1] right there above, after giving the
correct way to make the change.
> After the error,
>>>> tup[1]
> [4, 5, 6, 7, 8, 9]
This is exactly what I posted.
>>>> tup
> ([1, 2, 3], [4, 5, 6, 7, 8, 9])
This is a repeat of the same thing and adds no new info.
> The "bug" I refer to is that despite giving the TypeError, the tuple
> allowed the assignment of the mutated list to replace the original list.
No it did not. As MRAB noted, the list is mutated and the attempted
assignment causes an exeption. This has been discussed before more than
once ever since augmented *assignment* was introduced.
>>> tup = ([],[])
>>> id(tup[1])
711662188872
>>> tup[1] += [1]
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
tup[1] += [1]
TypeError: 'tuple' object does not support item assignment
>>> tup[1]
[1]
>>> id(tup[1])
711662188872
>>> tup[1] = tup[1].extend([2])
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
tup[1] = tup[1].extend([2])
TypeError: 'tuple' object does not support item assignment
>>> tup[1]
[1, 2]
>>> id(tup[1])
711662188872
Reading the augmented assignment doc carefully should make it clear that
"tup[1] += [1]" is the same as "tup[1] = tup[1].extend([2])" except that
evaluation of "tup[1]" happens just once instead of twice.
--
Terry Jan Reedy
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web