list slice and generators

Pavlos Parissis pavlos.parissis at gmail.com
Wed Nov 25 15:43:20 EST 2015


On 25/11/2015 11:07 πμ, Peter Otten wrote:
> Pavlos Parissis wrote:
> 
>> Hi,
>>
>> Do you see any possible dangerous hidden bug in the below code(using
>> python2.7 and python3.4)?
>>
>> My goal is to avoid go through the metrics list twice. But, I don't
>> know if there will be a problem with doing in place replace of list
>> elements using 2 generators.
>>
>> # metrics = ['', '0', '10'....]
>> metrics = [x.metric(name) for x in self._server_per_proc]
>> metrics[:] = (converter(x) for x in metrics)
>> metrics[:] = (x for x in metrics if x is not None)
> 
> Both generators are executed immediately, and the right side is always 
> evaluated before the the slice assignment. Try
> 

This is what I was vaguely remembering, thanks for the confirmation.

> metrics = (x.metric(name) for x in self._server_per_proc)
> metrics = (converter(x) for x in metrics)
> metrics = [x for x in metrics if x is not None]
> 

I see you prefer to bind the result of the evaluation to the same
variable. I learned (the hard way) that it could lead to problems where::

In [1]: a = [1, 2, 3]

In [2]: b = a

In [3]: a == b, a is b
Out[3]: (True, True)

In [4]: a = (x for x in a if x >1)

In [5]: a == b, a is b
Out[5]: (False, False)

In [6]: a
Out[6]: <generator object <genexpr> at 0x7f7f8b7400d8>

In [7]: list(a)
Out[7]: [2, 3]

In [8]: a = [1, 2, 3]

In [9]: b = a

In [10]: a == b, a is b
Out[10]: (True, True)

In [11]: a = [x for x in a if x >1]

In [12]: a == b, a is b
Out[12]: (False, False)

In [13]: a
Out[13]: [2, 3]

In [14]: b
Out[14]: [1, 2, 3]

Thus, I always use slice assignment, even when above case isn't applied.

> or
> 
> metrics = (converter(x.metric(name)) for x in self._server_per_proc)
> metrics = [x for x in metrics if x is not None]
> 

I should do the above.

> to get down to one intermediate list. Avoiding the last one is a bit tricky:
> 
> metrics = (converter(x.metric(name)) for x in self._server_per_proc)
> metrics = (x for x in metrics if x is not None)
> try:
>     # if there is at least one item the generator is not empty
>     first = next(metrics)
> except StopIteration:
>     metrics = ()
> else:
>     # put the first item back in
>     metrics = itertools.chain([first], metrics)
>     assert metrics
> 

Tricky, indeed

Thanks for your time and effort to answer my question, it is very
much appreciated.

Cheers,
Pavlos

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://mail.python.org/pipermail/python-list/attachments/20151125/e39fa24a/attachment.sig>


More information about the Python-list mailing list