Brainfuck code optimization in Python I wrote a program to automatically optimize my Brainfuck source files. It works well, but the optimizations are only trivial ones and probably there are still some other points to improve.

def main():

    print "Enter the path of a brainfuck source file you want to optimize"
    path = raw_input()
    if path in ('exit', 'quit', 'close'):
        exit()
    f = open(path, 'r')
    text = f.read()
    f.close()
    cmd = '' # removing comments and whitespaces
    for c in text:
        if c in ('+', '-', '&lt;', '&gt;', '.', ',', '[', ']'):
            cmd += c
    found = True
    while found:
        length = len(cmd)
        found = False
        for i in range(length-1):
            if cmd[i:i+2] in ('+-', '-+', '&lt;&gt;', '&gt;&lt;'):
                cmd = cmd[0:i] + cmd[i+2:length] # removing useless instruction pairs
                found = True
    ending = ''
    for i in range(len(path)):
        if path[i] == '.':
            ending = path[i:len(path)]
            path = path[0:i]
            break
    path = path + '_opt' + ending
    f = open(path, 'w')
    f.write(cmd)
    f.close()

if __name__ == '__main__':
    while True:
        main()


EDIT:
I'm considering about removing whole brackets, if it is obvious that they are never called. This is the case, if an opening bracket is directly after a closing bracket (][), because the first loop only breaks if the current cell value is zero and that means, that either the pointer or the cell value has to change to make the second loop work. However, unlike the other optimizations, I can't just remove ][, it should remove everything between [and the matching ] (including [ and ]). Are there any other cases I could remove unnecessary brainfuck code?
Some quick remarks:

You should be using the with..as construct when opening a file to ensure it is always closed, even if some intermediate code raises an exception:

with open(path) as f:
    text = f.read()
...
with open(path, 'w') as f:
    f.write(cmd)


I would save the comment commands in a set and outside of the loop. in is O(1) for sets and O(n) for tuples (even though n=4 here).

cmds = {'+-', '-+', '&lt;&gt;', '&gt;&lt;'}
found = True
while found:
    length = len(cmd)
    found = False
    for i in range(length-1):
        if cmd[i:i+2] in cmds:
            cmd = cmd[0:i] + cmd[i+2:length] # removing useless instruction pairs
            found = True


I would do the same with the longer command tuple before that:

comment_codes = {'+', '-', '&lt;', '&gt;', '.', ',', '[', ']'}
for c in text:
    if c in comment_codes:
        cmd += c


You could also use a generator comprehension and str.join here:

comment_codes = {'+', '-', '&lt;', '&gt;', '.', ',', '[', ']'}
cmd = "".join(c for c in text if c in comment_codes)


Your building of the output filename can be simplified using split and could use str.format:

name, ext = path.split('.')
path = '{}_opt.{}'.format(name, ext)