+ 2

About 'any' and 'all'

When you write an if condition like 'if x or y' and y is not defined but x is, there will be no NameError, everything's fine. If you try the same with 'any(x, y)' it will produce a NameError. Why is this difference? I thought 'any' and 'all' are supposed to only look until they have the answer, so wouldn't it be logical if they behaved like that 'if' example?

24th Aug 2018, 3:01 PM
HonFu
HonFu - avatar
8 ответов
+ 2
@Sergey Ushakov You have definitely confused between iterables and iterators. A simple list object is in fact an iterable. Check this link https://stackoverflow.com/questions/9884132/what-exactly-are-iterator-iterable-and-iteration ------------------ The difference is that we're using a list object literal, whereas the stackoverflow example is using a generator expression. In our example, all the items in our list is evaluated *before* it is passed as an argument to the any() function. As a result, the exception is raised from the file any() was called, and not within the any() function itself. But a generator expression is an iterator, meaning that it doesn't evaluate it's items till it is iterated over, or it's __next__() method is called (which is what a for loop does by the way). This is why the iterator wasn't exhausted and had a few items leftover. ------------------ The takeaway is that any() doesn't evaluate each of the iterable's items, it only does so till it finds a Truth-ey value, and then returns True. But if our iterable happens to be a list literal that we are making to pass into any(), then python has to evaluate each of it's items before passing it to any() (Because you can't create a list object without evaluating it's values).
24th Aug 2018, 10:40 PM
Just A Rather Ridiculously Long Username
+ 2
Good question! This happens because the 'or' operator doesn't evaluate the second operand when its first it true. Your example is perfect for this. But when you make a list object, all of its values must be evaluated because only then can you pass it into the any() function. ------------------- >>> 0 or print('foo') or False or print('x') or 1 or print('y') or None or print('bar') foo x 1 ^Only the expressions till the '1' is evaluated >>> [0, print('foo'), False, print('x'), 1, print('y'), None, print('bar')] foo x y bar [0, None, False, None, 1, None, None, None] ^All of the values are evaluated before the list object is created.
24th Aug 2018, 4:01 PM
Just A Rather Ridiculously Long Username
+ 1
any is a function. It's arguments should be resolved before execution.
24th Aug 2018, 3:28 PM
Sergey Ushakov
Sergey Ushakov - avatar
+ 1
Okay, then it would indirectly still impossible to pass an undefined object to any/all, because it shouldn't be possible to generate an iterator using undefined elements. So either it's constructed cleanly from the start, or it (being for example a list) has already been evaluated in the moment of creation. And any/all would be just evading reading that collection AGAIN, except to the point where the function's question has been answered... But since it recognizes the mistake (that an identifier has no value), it must have read the list in some way, right? Are these two qualitatively different processes (quick and slow) dismissing a list because of a NameError and scanning the items for boolean value? Also in that if condition I can not write anything: An empty name will be ignored but not a messed up syntax. That makes it a 'conscious' decision of python to let it go, right? 'Okay, the coder has put an empty variable here, but syntax is alright so let' s go on with business ...'
25th Aug 2018, 6:17 AM
HonFu
HonFu - avatar
0
Actually I asked about this after reading this: https://stackoverflow.com/questions/19389490/how-do-pythons-any-and-all-functions-work There was some argumentation about the shortcutting behaviour of the two functions: 'Another important thing to know about any and all is, it will short-circuit the execution, the moment they know the result. The advantage is, entire iterable need not be consumed.' But if the whole iterable is analyzed anyway when passing it as an argument, where is the shortcut? Or is the evaluation that finds the NameError different (and considerably less time-consuming or whatever) than the process of checking one by one for True or False?
24th Aug 2018, 4:15 PM
HonFu
HonFu - avatar
0
The iterable objects isn't a simple list. Iterable construct it's items by request. For example range(1000) will not construct 1000 integers at once, but return them one by one.
24th Aug 2018, 7:03 PM
Sergey Ushakov
Sergey Ushakov - avatar
0
Okay, Sergey, but if the list is not analyzed at once, how, in the given example, can Python call NameError, when executing a function? This is not about range or some iterobject, but about any container that is handed over to the function 'any' or 'all', like: any(aa, ab,... zz). ... with variable zz being not defined.
24th Aug 2018, 9:24 PM
HonFu
HonFu - avatar
0
Just A Rather Ridiculously Long Username Yes, list is iterable. I say that iterable is bigger then simple list. It is impossible to construct list without consulting it's elements, while iterable allows it.
25th Aug 2018, 5:55 AM
Sergey Ushakov
Sergey Ushakov - avatar