Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this cellular-automaton code work perfectly well in Python 3.x but not in Python 2.x?

I have following code (produces an elementary cellular automaton):

def cellular_automaton(init_string,pattern,gens):
    values=[128,64,32,16,8,4,2,1]
    pattern_list=[]
    k=0
    while k<len(values):
        if values[k]+sum(pattern_list)<=pattern:
            pattern_list.append(values[k])
        k=k+1



    i=0
    j=0
    b=[]
    f=''

    pos_init=[0,1,0]
    pos_interm=[]
    pos_init=[[n,n+1,n] for n in range(len(init_string)-1)]
    pos_interm.append(pos_init)
    pos_interm[-1][-1].append(len(init_string)-1)
    pos_interm[-1][-1].append(0)
    pos_interm[0][0].insert(0,len(init_string)-1)
    pos_interm2=[val for subl in pos_interm for val in subl]
    pos=[val for subl in pos_interm2 for val in subl]

    b.append(pos)
    while j<gens:
        pos=[i+len(init_string) for i in pos]
        b.append(pos)
        j=j+1
        c=[val for subl in b for val in subl]



    while i<len(c):
        if init_string[c[i]]=='.' and init_string[c[i+1]]=='.' and init_string[c[i+2]]=='.':
            if 1 in pattern_list:
                init_string=init_string+'x'
            else:
                init_string=init_string+'.'
        elif init_string[c[i]]=='.' and init_string[c[i+1]]=='.' and init_string[c[i+2]]=='x':
            if 2 in pattern_list:
                init_string=init_string+'x'
            else:
                init_string=init_string+'.'
        elif init_string[c[i]]=='.' and init_string[c[i+1]]=='x' and init_string[c[i+2]]=='.':
            if 4 in pattern_list:
                init_string=init_string+'x'
            else:
                init_string=init_string+'.'
        elif init_string[c[i]]=='.' and init_string[c[i+1]]=='x' and init_string[c[i+2]]=='x':
            if 8 in pattern_list:
                init_string=init_string+'x'
            else:
                init_string=init_string+'.'
        elif init_string[c[i]]=='x' and init_string[c[i+1]]=='.' and init_string[c[i+2]]=='.':
            if 16 in pattern_list:
                init_string=init_string+'x'
            else:
                init_string=init_string+'.'
        elif init_string[c[i]]=='x' and init_string[c[i+1]]=='.' and init_string[c[i+2]]=='x':
            if 32 in pattern_list:
                init_string=init_string+'x'
            else:
                init_string=init_string+'.'
        elif init_string[c[i]]=='x' and init_string[c[i+1]]=='x' and init_string[c[i+2]]=='.':
            if 64 in pattern_list:
                init_string=init_string+'x'
            else:
                init_string=init_string+'.'
        elif init_string[c[i]]=='x' and init_string[c[i+1]]=='x' and init_string[c[i+2]]=='x':
            if 128 in pattern_list:
               init_string=init_string+'x'
            else:
                init_string=init_string+'.'





        i=i+3





    return init_string[(len(pos_interm2)+1)*-2:(len(pos_interm2)+1)*-1]

The output is produced is as follows:

print cellular_automaton('.x.x.x.x.', 17, 2)

This code works perfectly well in Python 3.3.2 but produces a 'string index out of range' error in Python 2.7:

Traceback (most recent call last):
  File "vm_main.py", line 33, in <module>
    import main
  File "/tmp/vmuser_trwqmlfqgq/main.py", line 143, in <module>
    print cellular_automaton('.x.x.x.x.', 17, 2)
  File "/tmp/vmuser_trwqmlfqgq/main.py", line 95, in cellular_automaton
    if init_string[c[i]]=='.' and init_string[c[i+1]]=='.' and init_string[c[i+2]]=='.':
IndexError: string index out of range

I'm not so familiar with the differences between Py2 and Py3, so I'd be glad if anyone could help me find out what is to be done to make it work in Python 2.7 as well. How come it produces this Index error in Py2?

like image 251
Revilo79 Avatar asked May 03 '26 02:05

Revilo79


1 Answers

pos=[i+len(init_string) for i in pos]

In Python 2, this will leak out the last value of i overwriting your original initialized value of 0. As such, Python 2 will start at index 8 which will later result in the index errors.

To fix this, just give that variable a different name:

pos=[k+len(init_string) for k in pos]

To show a clearer example of this, you can test this in an interpreter session. Python 3 will correctly keep the original value of i:

>>> i = 0
>>> [i for i in range(5)]
[0, 1, 2, 3, 4]
>>> i
0

Python 2 however will keep the last value of the loop within the list comprehension:

>>> i = 0
>>> [i for i in range(5)]
[0, 1, 2, 3, 4]
>>> i
4

For more on this change, see also this answer.

like image 58
poke Avatar answered May 05 '26 14:05

poke