Re: [Python-ideas] How assignment should work with generators?

I would like to mention that the issue of assignment to a target list, is also relevant to the case of elementwise assignment to a mutable sequence (e.g. lists and arrays). Here as well, the rhs of the assignment statement states the number of elements to be assigned. Consequently, the following example will get into infinite loop:
Writing "A[:2] = count()" will cause the same result. Here as well, it is currently safer to use islice if the rhs is a generator or an iterator. e.g.:
it = count() A[:] = islice(it,2)
In my opinion, it is be better to devise a solution that could be applied in both cases. Maybe a new kind of assignment operator that will be dedicated to this kind of assignment. i.e. elementwise assignment with restriction on the number of elements to be assigned, based on the length of the lhs object (or the number of targets in the target list).

On Wed, Nov 29, 2017 at 5:46 AM, Alon Snir <AlonSnir@hotmail.com> wrote:
Hmm. The trouble is that slice assignment doesn't have a fixed number of targets. If you say "x, y = spam", there's a clear indication that 'spam' needs to provide exactly two values; but "A[:] = spam" could have any number of values, and it'll expand or shrink the list accordingly. ChrisA

On 28/11/17 18:46, Alon Snir wrote:
Actually the "infinite loop" will terminate when you run out of memory, but that's a mere detail.
Not so much "safer" as "correct", I'm afraid. In the first case you asked for an infinite sequence, in the second case you asked for a finite one.
In my opinion, it is be better to devise a solution that could be applied in both cases. Maybe a new kind of assignment operator that will be dedicated to this kind of assignment. i.e. elementwise assignment with restriction on the number of elements to be assigned, based on the length of the lhs object (or the number of targets in the target list).
Flatly, no. It is better not to ask for things you don't want in the first place, in this case the infinite sequence. Still, don't let me discourage you from working on this. If you can define how such an assignment would work, or even the length of A[:] as an assignment target, I'm not going to dismiss it out of hand. -- Rhodri James *-* Kynesim Ltd

On Tue, Nov 28, 2017 at 06:46:18PM +0000, Alon Snir wrote:
"This damn computer always does what I tell it to do, instead of what I wanted!" What exactly did you expect to happen? To me, this feels like a complaint that writing `while True: pass` enters an infinite loop.
This isn't merely a matter of safety. (Python is pretty safe -- I can interrupt most infinite loops with Ctrl-C.) It is a matter of actually telling the interpreter what you want it to do. How do you expect the interpreter to predict that you wanted two items, rather than three, or thirty-three? This has little to do with iterators or generators. count() is a rare and special case because it is by design an infinite iterator. Slice assignment is perfectly "safe" with finite iterators: py> a = [] py> a[:] = iter([1, 2, 3, 4, 5]) py> a [1, 2, 3, 4, 5] Slice assignment allows the number of targets and number of values to vary independently. I can do this: a[1:4] = range(10) and Python will happily replace the three slots on the left with the ten items on the right. Or vice versa: a[1:11] = range(4) That is by design, not a bug, and the consequence is that you have to be explicit (on both the left and the right) about how many slots you want to replace and how many items you want to replace them with. We cannot infer one from the other, since they can vary independently.
In my opinion, it is be better to devise a solution that could be applied in both cases.
We already have that solution. py> from itertools import count, islice py> a = [] py> it = count() py> a[:] = islice(it, 5) py> a[:2] = islice(it, 2) py> a[:0] = islice(it, 3) py> a [7, 8, 9, 5, 6, 2, 3, 4]
I doubt that would work in your original case: a = [] a[:] = count() Since the list is empty, it would assign zero items from the right, which would make it a no-op. Surely that's not what you want? -- Steve

On Wed, Nov 29, 2017 at 5:46 AM, Alon Snir <AlonSnir@hotmail.com> wrote:
Hmm. The trouble is that slice assignment doesn't have a fixed number of targets. If you say "x, y = spam", there's a clear indication that 'spam' needs to provide exactly two values; but "A[:] = spam" could have any number of values, and it'll expand or shrink the list accordingly. ChrisA

On 28/11/17 18:46, Alon Snir wrote:
Actually the "infinite loop" will terminate when you run out of memory, but that's a mere detail.
Not so much "safer" as "correct", I'm afraid. In the first case you asked for an infinite sequence, in the second case you asked for a finite one.
In my opinion, it is be better to devise a solution that could be applied in both cases. Maybe a new kind of assignment operator that will be dedicated to this kind of assignment. i.e. elementwise assignment with restriction on the number of elements to be assigned, based on the length of the lhs object (or the number of targets in the target list).
Flatly, no. It is better not to ask for things you don't want in the first place, in this case the infinite sequence. Still, don't let me discourage you from working on this. If you can define how such an assignment would work, or even the length of A[:] as an assignment target, I'm not going to dismiss it out of hand. -- Rhodri James *-* Kynesim Ltd

On Tue, Nov 28, 2017 at 06:46:18PM +0000, Alon Snir wrote:
"This damn computer always does what I tell it to do, instead of what I wanted!" What exactly did you expect to happen? To me, this feels like a complaint that writing `while True: pass` enters an infinite loop.
This isn't merely a matter of safety. (Python is pretty safe -- I can interrupt most infinite loops with Ctrl-C.) It is a matter of actually telling the interpreter what you want it to do. How do you expect the interpreter to predict that you wanted two items, rather than three, or thirty-three? This has little to do with iterators or generators. count() is a rare and special case because it is by design an infinite iterator. Slice assignment is perfectly "safe" with finite iterators: py> a = [] py> a[:] = iter([1, 2, 3, 4, 5]) py> a [1, 2, 3, 4, 5] Slice assignment allows the number of targets and number of values to vary independently. I can do this: a[1:4] = range(10) and Python will happily replace the three slots on the left with the ten items on the right. Or vice versa: a[1:11] = range(4) That is by design, not a bug, and the consequence is that you have to be explicit (on both the left and the right) about how many slots you want to replace and how many items you want to replace them with. We cannot infer one from the other, since they can vary independently.
In my opinion, it is be better to devise a solution that could be applied in both cases.
We already have that solution. py> from itertools import count, islice py> a = [] py> it = count() py> a[:] = islice(it, 5) py> a[:2] = islice(it, 2) py> a[:0] = islice(it, 3) py> a [7, 8, 9, 5, 6, 2, 3, 4]
I doubt that would work in your original case: a = [] a[:] = count() Since the list is empty, it would assign zero items from the right, which would make it a no-op. Surely that's not what you want? -- Steve
participants (4)
-
Alon Snir
-
Chris Angelico
-
Rhodri James
-
Steven D'Aprano