4

Based on what I've seen on other stackoverflow pages:

the following code should short circuit:

any([True, 2+2, False, 2/0])
all([True, 2+2, False, 2/0])

but for every one of them I get a ZeroDivisionError: division by zero.

Am I missing something? Why does it error?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
hainabaraka
  • 595
  • 2
  • 5
  • 13
  • 1
    `False and 2/0` and `True and 2/0` short circuit evaluation happens – bigbounty Jul 20 '20 at 02:51
  • After reviewing the links, I decided that a) https://stackoverflow.com/questions/17246388 should be the canonical version of the question; b) what you are asking is not a separate question, but an important clarification that was not properly covered there. So I added duplicate links and wrote my own answer there. – Karl Knechtel Aug 02 '22 at 22:29

2 Answers2

4

Your code errors because the expressions have to be evaluated before being passed into the function.

In this context, short-circuiting actually means that as soon as they find a different value, they return and don't bother checking the remaining values. It's not the same kind of short-circuiting that and and or do, which can actually avoid evaluating expressions.

To illustrate, let's use an iterator, which will get consumed:

>>> a = iter([1, 0, 2, 3])
>>> all(a)  # Search until a falsy value
False
>>> list(a)  # Show what's left in the iterator
[2, 3]

You can see that it consumed 1 and 0, returning on 0 because it's falsy.


Now, if you did want to do lazy evaluation with any and all, you could call lambdas in a generator expression:

>>> any(e() for e in [lambda: 1, lambda: 0, lambda: 2/0])
True
>>> all(e() for e in [lambda: 1, lambda: 0, lambda: 2/0])
False

(Thanks to this question for inspiring this bit.)

wjandrea
  • 28,235
  • 9
  • 60
  • 81
1

Yes, short circuting happens in python

In [23]: False and 3/0
Out[23]: False

In [24]: True and 3/0
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-24-a08823d6496a> in <module>
----> 1 True and 3/0

ZeroDivisionError: division by zero

Using the dis module,

In [32]: dis.dis("all([True, 2+2, False, 2/0])")
  1           0 LOAD_NAME                0 (all)
              2 LOAD_CONST               0 (True)
              4 LOAD_CONST               1 (4)
              6 LOAD_CONST               2 (False)
              8 LOAD_CONST               3 (2)
             10 LOAD_CONST               4 (0)
             12 BINARY_TRUE_DIVIDE
             14 BUILD_LIST               4
             16 CALL_FUNCTION            1
             18 RETURN_VALUE

In [33]: dis.dis("any(True, 2+2, False, 2/0)")
  1           0 LOAD_NAME                0 (any)
              2 LOAD_CONST               0 (True)
              4 LOAD_CONST               1 (4)
              6 LOAD_CONST               2 (False)
              8 LOAD_CONST               3 (2)
             10 LOAD_CONST               4 (0)
             12 BINARY_TRUE_DIVIDE
             14 CALL_FUNCTION            4
             16 RETURN_VALUE

When you look at the function calls, BINARY_TRUE_DIVIDE is evaluated before any or all because expressions get evaluated first before any function call

bigbounty
  • 16,526
  • 5
  • 37
  • 65