Mailing List Archive

Subtle difference between any(a list) and any(a generator) with Python 3.9
Hello

Reading PEP572 about Python 3.9 assignment expressions,
I discovered a subtle difference between any(a list)
and any(a generator)

see:

>>> lines = ["azerty", "#qsdfgh", "wxcvbn"]
>>> any((comment := line).startswith('#') for line in lines)
True
>>> comment
"#qsdfgh"

>>> any([(comment := line).startswith('#') for line in lines])
True
>>> comment
'wxcvbn'

The two code snippets which seems very similar provide a
different value for "comment".

When "any" deals with a generator, it stops as soon it finds
a True value and returns True.

When "any" deals with a list, the whole list is calculated
first, and then "any" looks for a True.

Before 3.9 and the walrus operator, the two ways always provide
the same result, in a faster way with a generator.

With 3.9 and the walrus operator, result can be different








--
https://mail.python.org/mailman/listinfo/python-list
Re: Subtle difference between any(a list) and any(a generator) with Python 3.9 [ In reply to ]
On Thu, Jul 29, 2021 at 7:49 PM ast <ast@invalid> wrote:
>
> Hello
>
> Reading PEP572 about Python 3.9 assignment expressions,
> I discovered a subtle difference between any(a list)
> and any(a generator)
>
> see:
>
> >>> lines = ["azerty", "#qsdfgh", "wxcvbn"]
> >>> any((comment := line).startswith('#') for line in lines)
> True
> >>> comment
> "#qsdfgh"
>
> >>> any([(comment := line).startswith('#') for line in lines])
> True
> >>> comment
> 'wxcvbn'

"any" is irrelevant here. What you're seeing is that a list
comprehension is evaluated fully, and a generator expression isn't.
That's exactly what they're meant to do :)

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: Subtle difference between any(a list) and any(a generator) with Python 3.9 [ In reply to ]
On 7/29/2021 5:39 AM, Unknown wrote:
> Hello
>
> Reading PEP572 about Python 3.9 assignment expressions,
> I discovered a subtle difference between any(a list)
> and any(a generator)
>
> see:
>
> >>> lines = ["azerty", "#qsdfgh", "wxcvbn"]
> >>> any((comment := line).startswith('#') for line in lines)
> True
> >>> comment
> "#qsdfgh"
>
> >>> any([(comment := line).startswith('#') for line in lines])

Same as

>>> booleans = [(comment := line).startswith('#') for line in lines]
>>> # comment == last item.
>>> any(booleans) # Iteration though booleans stops at 1st True.

> True
>>> comment
> 'wxcvbn'
>
> The two code snippets which seems very similar provide a
> different value for "comment".
>
> When "any" deals with a generator, it stops as soon it finds
> a True value and returns True.
>
> When "any" deals with a list, the whole list is calculated
> first, and then "any" looks for a True.
>
> Before 3.9 and the walrus operator, the two ways always provide
> the same result, in a faster way with a generator.

Since the 'two ways' involve the new :=, I have no idea what 'two ways'
and 'same result' you mean before :=.

> With 3.9 and the walrus operator, result can be different



--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list
Re: Subtle difference between any(a list) and any(a generator) with Python 3.9 [ In reply to ]
On Fri, Jul 30, 2021 at 5:40 AM Terry Reedy <tjreedy@udel.edu> wrote:
> Since the 'two ways' involve the new :=, I have no idea what 'two ways'
> and 'same result' you mean before :=.
>

I'm not sure, but I think that a lot of people read patch notes as if
they say "this is how everyone needs to do things now", and then blame
or credit the newest features with everything that happens.

Personally, I'd search for the comments like this:

for line in lines:
if line.startswith("#"):
... # whatever you do if there is one
break
else:
... # whatever you do if there isn't one

But if you have to do it with a one-liner, much cleaner to use next on
your filter:

comment = next((l for l in lines if l.startswith("#")). None)

Neither of these depends on :=. I don't know what "two ways" there
are, but capturing the first element that matches a filter is a pretty
normal thing to do.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list