Too Many if Statements?
Bengt Richter
bokr at oz.net
Sun Feb 12 14:27:51 EST 2006
On Sat, 11 Feb 2006 15:40:49 -0500, "Terry Reedy" <tjreedy at udel.edu> wrote:
>
>"Steve Holden" <steve at holdenweb.com> wrote in message
>news:dsid2f$b99$1 at sea.gmane.org...
>> Clearly it would be a good idea to remove whatever problem is causing
>> the error,
>
>The problem (see my post of the com_backpatch code) is writing a compound
>statement (here a for loop) with a body so large as to require a jump of
>more than 64K bytes in the compiled bytecode (ie, from the test at the top
>of the loop to the code that follows after the loop). Until the jump limit
>is raised (likely a long wait ;-), the OP must factor some of the code out
>of the loop.
>
Easy example:
>>> def test(n):
... while True:
... try: co = compile('if x:\n'+ n*' a=1\n','','exec')
... except Exception,e: break
... n += 1
... print 'Stopped at n=%s due to %s: %s'%(n, e.__class__.__name__,e)
...
get an idea of where to start that:
>>> import dis
>>> n=3
>>> dis.dis( compile('if x:\n'+ n*' a=1\n','','exec'))
1 0 LOAD_NAME 0 (x)
3 JUMP_IF_FALSE 22 (to 28)
6 POP_TOP
2 7 LOAD_CONST 0 (1)
10 STORE_NAME 1 (a)
3 13 LOAD_CONST 0 (1)
16 STORE_NAME 1 (a)
4 19 LOAD_CONST 0 (1)
22 STORE_NAME 1 (a)
25 JUMP_FORWARD 1 (to 29)
>> 28 POP_TOP
>> 29 LOAD_CONST 1 (None)
32 RETURN_VALUE
>>> (2**16-7)/(13-7)
10921
back off 1
>>> test(10920)
Stopped at n=10922 due to SystemError: com_backpatch: offset too large
Decided to test the exact 65536 jump with code chunks of 16 byte-codes and one
chunk at the end to make 16 with the last JUMP_FORWARD.
>>> n=4095
>>> dis.dis( compile('if x:\n'+ n*' a=1+2,4 \n'+' x=0,x','','exec'))
Traceback (most recent call last):
File "<stdin>", line 1, in ?
SystemError: com_backpatch: offset too large
>>> n=4094
>>> dis.dis( compile('if x:\n'+ n*' a=1+2,4 \n'+' x=0,x','','exec'))
1 0 LOAD_NAME 0 (x)
3 JUMP_IF_FALSE 65520 (to 65526)
6 POP_TOP
2 7 LOAD_CONST 0 (1)
10 LOAD_CONST 1 (2)
13 BINARY_ADD
14 LOAD_CONST 2 (4)
17 BUILD_TUPLE 2
20 STORE_NAME 1 (a)
3 23 LOAD_CONST 0 (1)
So the corner case of 2**16 is ok. Believe it or not, I once discovered a compiler
error based on optimizing a 2**16-involving loop condition as if it were 0 and the
loop didn't execute! IIRC, I bumped into it processing an array of records with a stride of
exactly 2**n and it thought it could calculate a 16-bit number of strides for end of loop.
No good for arraysize/stridesize==2**16 ;-)
If the OP really HAD to, he could always (untested) break
if cond:
too
large
else:
two
large,also
into
if cond:
too
else:
two
if cond:
large
else:
large,also
but that reads gawdawfully. (So, I imagine, does about any code hitting the offset limit ;-)
If it's a matter of too many elifs, the OP could break that more readably, e.g. (untested)
done=True
if cond:
bla
elif c2:
bla 2
...
elif c456:
bla456
else:
done=False
more, done = not done,True
if more and c457:
bla c457
elif c458:
bla458
...
elif c1012:
bla1012
else:
done = False
more, done = not done,True
... etc
But the OP should find another approach I think,
because this is still disgusting code ;-)
Regards,
Bengt Richter
More information about the Python-list
mailing list