What does "for x in y or z:" do in Python?
Asked Answered
G

2

16

I'm trying to take apart and de-obfuscate this mandlebrot-generating python code:

_                                      =   (
                                        255,
                                      lambda
                               V       ,B,c
                             :c   and Y(V*V+B,B,  c
                               -1)if(abs(V)<6)else
               (              2+c-4*abs(V)**-0.4)/i
                 )  ;v,      x=1500,1000;C=range(v*x
                  );import  struct;P=struct.pack;M,\
            j  ='<QIIHHHH',open('M.bmp','wb').write
for X in j('BM'+P(M,v*x*3+26,26,12,v,x,1,24))or C:
            i  ,Y=_;j(P('BBB',*(lambda T:(T*80+T**9
                  *i-950*T  **99,T*70-880*T**18+701*
                 T  **9     ,T*i**(1-T**45*2)))(sum(
               [              Y(0,(A%3/3.+X%v+(X/v+
                               A/3/3.-x/2)/1j)*2.5
                             /x   -2.7,i)**2 for  \
                               A       in C
                                      [:9]])
                                        /9)
                                       )   )

source: http://preshing.com/20110926/high-resolution-mandelbrot-in-obfuscated-python/
I found a for loop with an interesting twist, and I'm not sure if it's just part of the obfuscation, or if it actually has a function. The middle line:
for X in j('BM'+P(M,v*x*3+26,26,12,v,x,1,24))or C:
What does the or do at the end?

I re-wrote the code as follows for clarity:

import struct

image_name = "M.bmp"
mandlebrot = lambda V,B,c :c and Y(V*V+B,B,c-1) if(abs(V)<6) else (2+c-4*abs(V)**-0.4)/i
y,x = 600,800
pixelrange = range(y*x)
package = struct.pack

image = open(image_name,'wb').write

for X in image('BM'+package('<QIIHHHH',y*x*3+26,26,12,y,x,1,24)) or pixelrange:
  i = 255
  Y = mandlebrot
  image(package('BBB',*(lambda T:(T*80+T**9*i-950*T**99,T*70-880*T**18+701*T**9,T*i**(1-T**45*2)))(sum([Y(0,(A%3/3.+X%y+(X/y+A/3/3.-x/2)/1j)*2.5/x-2.7,i)**2 for A in pixelrange [:9]])/9)))
Gallantry answered 15/11, 2013 at 20:4 Comment(2)
The whole story of how you found this interesting for x in y or z is not necessary to the question, but I'm glad you included it. It's pretty cool.Hamforrd
I was expecting the answer to be a lot more complex, because I did not know "for x in y or z" is actually a proper/valid use of a for loop. As usual, python suprised me with its simplicity.Gallantry
G
18

Doing:

for x in y or z:

is the same as:

for x in (y or z):

If y evaluates to True, the for-loop will iterate through it. Otherwise, it will iterate through z.

Below is a demonstration:

>>> y = [1, 2, 3]
>>> z = [4, 5, 6]
>>> for x in y or z:
...     print x
...
1
2
3
>>> y = [] # Empty lists evaluate to False in Python
>>> for x in y or z:
...     print x
...
4
5
6
>>>
Gunnel answered 15/11, 2013 at 20:6 Comment(1)
It's amazing how powerful a quick test in the cli can be.Supplicant
I
3

or returns the first operand if it is boolean true, otherwise the second. Boolean false basically means 0, False, None, or an "empty object" (empty string, list, etc.); boolean true is everything else. So j('BM'+P(M,v*x*3+26,26,12,v,x,1,24)) or C will evaluate to the result of the j(...) call if that result is nonempty, otherwise to C. So it will iterate over the result of j(...) if that result is nonempty, otherwise it will iterate over C.

Infertile answered 15/11, 2013 at 20:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.