The previous answers somewhat assume the reader is already familiar with the syntax and generators. I'd like to explain more for people who aren't.
The snippet
any(x % 2 for x in a)
is short syntax for:
any((x % 2 for x in a))
So what's happening is that (x % 2 for x in a)
gets evaluated and the result value is then given to the any
function. Just like print(21 * 2
) computes the value 42, which is then given to the print
function.
The expression (x % 2 for x in a)
is a generator expression and its result is a generator iterator. That is an object that computes and hands out its values on demand. So in this case, when asked for a value, this iterator looks at the next value from a
, computes its remainder modulo 2 (i.e., 0 for even and 1 for odd), and hands out that value. And then literally waits for possibly getting asked again for another value.
The any
function is a second actor here. It gets the iterator as its argument, and then asks the iterator for more and more values, hoping for one that's true (note that 1 is true and 0 is false).
You can really think of it as two different persons interacting. The any-guy asking the iterator-guy for values. Again, note that the iterator-guy does not compute all values in advance. Only one at a time, whenever the any-guy asks for the next value. So it's really a back-and-forth between the two guys.
In the case of any(x % 2 for x in a)
, the iterator-guy, whenever asked by the any-guy for the next value, just computes one modulo value, hands it to the any-guy, and the any-guy has to judge it. Here the iterator-guy is like an incompetent junior developer, involving the manager for every single number, somewhat forcing them to hardcore micro-manage.
In the case of any(True for x in a if x % 2)
, the iterator-guy, whenever asked by the any-guy for the next value, doesn't mindlessly hand over just the modulo values. Instead, this iterator-guy judges the values himself, and only hands over something to the manager when there's something worthy to hand over. Namely only when he discovers an odd value (in which case he doesn't hand over 0
or 1
, but True
). Here the iterator-guy is like a competent senior developer doing all the work, and the manager can totally lay back and chill (and at the end of the day still take all the credit).
It should be clear that the second way is much more efficient, as they don't needlessly communicate for every ... single ... input number. Especially since your input a = [0] * 10000000
doesn't contain any odd numbers. The junior developer reports ten million zeros to the manager who has to judge all of them. With a constant back-and-forth between them for every zero. The senior developer judges all himself and reports nothing to his manager. Well, ok, both developers at the end additionally report that they're done, at which point the manager concludes False
as the result of the whole any(...)
expression).