Author rhettinger
Recipients Jonathan.Livni, georg.brandl, rhettinger
Date 2011-02-16.10:05:22
SpamBayes Score 3.7499e-09
Marked as misclassified No
Message-id <1297850725.78.0.47690318424.issue11221@psf.upfronthosting.co.za>
In-reply-to
Content
This is an interesting puzzle.  In both cases, the zip() function is called and runs to completion before either the list comprehension or genexp is started or called.  The code for all() is somewhat simple -- it iterates over the input and tests whether the value is true.  That is also the same in both.

one essential difference between the two then is that the x, y variables get exposed in the list comprehension but not in the genexp.  The only way I can see to get to two to evaluate differently is to mutate the exposed variables before the comparison:

>>> from decimal import *
>>> L = list(map(Decimal, '6.700 6.800 7.140 7.460 7.735'.split()))
>>> def f(z):
	global y
	y -= 100
	return z

>>> all([(f(x)<=y) for x, y in zip(L, L[1:])])
False
>>> all((f(x)<=y) for x, y in zip(L, L[1:]))
True

I don't see how that mutation could happen in your functions unless decimal has been subclassed to override its __le__ method.

Another way to get a midstream mutation is for L to change in mid-computation in multi-threaded code.  Is your example single threaded?  Is the debugger affecting the run in some way?

The disassembly shows 1) when zip is called, 2) whether x,y are exposed, and 3) whether a list is being iterated or the genexp:

>>> from dis import dis
>>> dis(compile('all((x<=y) for x, y in zip(a, b))', '', 'eval'))
  1           0 LOAD_NAME                0 (all)
              3 LOAD_CONST               0 (<code object <genexpr> at 0x16b3f50, file "", line 1>)
              6 MAKE_FUNCTION            0
              9 LOAD_NAME                1 (zip)
             12 LOAD_NAME                2 (a)
             15 LOAD_NAME                3 (b)
             18 CALL_FUNCTION            2
             21 GET_ITER            
             22 CALL_FUNCTION            1
             25 CALL_FUNCTION            1
             28 RETURN_VALUE        
>>> dis(compile('all([(x<=y) for x, y in zip(a, b)])', '', 'eval'))
  1           0 LOAD_NAME                0 (all)
              3 BUILD_LIST               0
              6 DUP_TOP             
              7 STORE_NAME               1 (_[1])
             10 LOAD_NAME                2 (zip)
             13 LOAD_NAME                3 (a)
             16 LOAD_NAME                4 (b)
             19 CALL_FUNCTION            2
             22 GET_ITER            
        >>   23 FOR_ITER                25 (to 51)
             26 UNPACK_SEQUENCE          2
             29 STORE_NAME               5 (x)
             32 STORE_NAME               6 (y)
             35 LOAD_NAME                1 (_[1])
             38 LOAD_NAME                5 (x)
             41 LOAD_NAME                6 (y)
             44 COMPARE_OP               1 (<=)
             47 LIST_APPEND         
             48 JUMP_ABSOLUTE           23
        >>   51 DELETE_NAME              1 (_[1])
             54 CALL_FUNCTION            1
             57 RETURN_VALUE  

Nothing else interesting pops-out.

One question out of curiousity.  In the JPG file that is attached, the return type is listed as bool_ instead of bool.  Is that normal for an eclipsed debugger values display?
History
Date User Action Args
2011-02-16 10:05:26rhettingersetrecipients: + rhettinger, georg.brandl, Jonathan.Livni
2011-02-16 10:05:25rhettingersetmessageid: <1297850725.78.0.47690318424.issue11221@psf.upfronthosting.co.za>
2011-02-16 10:05:23rhettingerlinkissue11221 messages
2011-02-16 10:05:22rhettingercreate