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

Wed Nov 29 14:33:54 EST 2017

```
On 28/11/2017 23:15, Alon Snir wrote:
> On Wed, Nov 29, 2017 at 5:46 AM, Alon Snir <AlonSnir at hotmail.com> wrote:
>> 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:
>>
>>>>> from itertools import count
>>>>> A = []
>>>>> A[:] = count()
>>
>> 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).
>>
>
> ChrisA 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.
>
> Rhodri James wrote:
> 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.
>
>
>
> The idea is to define an alternative assignment rule, that is to assign exactly as many elements as the current length of the lhs object (without expanding or shrinking it). Suppose "?=" is the operator for the alternative assignment rule; A=[None]*2; and "iterator" is any iterator (finite or infinite). In this case, the following code:
>
>>>> A ?= iterator
>
> would behave like this:
>
>>>> A[:] = islice(iterator, 2)  # where 2 is the length of A
>
> And as suggested earlier for the case of assignment to a target list, the following code:
>
>>>> x, y ?= iterator
>
> would behave like this:
>
>>>> x, y = islice(iterator, 2)  # where 2 is the number of targets
>
> Regarding the length issue:
> Is there any difficulty in finding the length of a sliced sequence? After all, the range object has a len method. Therefore, the length of A[s] (where s is a slice object) could be evaluated as follows:
>
>>>> len(range(*s.indices(len(A))))

Just a thought but what about a syntax something along the lines of:

a, b, *remainder = iterable

Where remainder becomes the iterable with the first two values consumed
by assigning to a & b. If the iterator has less than 2 values, (in the
above case), remaining it should error, if it has exactly 2 then
remainder would become an exhausted iterable. Of course the user could
also use:

a, b, *iterable = iterable

Others may differ but this syntax has a lot of similarity to the f(a, b,
*args) syntax, possibly enough that most users could understand it.

--