wobbily_col
wobbily_col

Reputation: 11891

can someone explain how this python code doesn't give an error

So I have inherited a rather crappy piece of code. Indentation is as I found it. Why does the else not throw an error? The code will never reach it as far as I understand.

    for l in range(1,9):
        indexes = pickle.load(open('%s_%d.pkl'%(fc,l)))

        clusters_sum = sum([indexes[i]['count'] for i in indexes])
        print >> out, 'Lane %d: %d clusters PF.\n%8s  %9s  %5s' % (l,clusters_sum,'Index','Count','%')
        for i in sorted(indexes, key=lambda x: indexes[x]['name']):
            pct = indexes[i]['count'] and indexes[i]['count']/clusters_sum*100 or 0
            if pct < 0.06: continue
            print >> out, '%8s  %9d  %5.1f' % (indexes[i]['name'], indexes[i]['count'], pct)
        else: print >> out

Upvotes: 0

Views: 169

Answers (3)

Mark Ransom
Mark Ransom

Reputation: 308206

for loops can have an else clause.

From http://docs.python.org/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops:

Loop statements may have an else clause; it is executed when the loop terminates through exhaustion of the list (with for) or when the condition becomes false (with while), but not when the loop is terminated by a break statement.

Since the loop doesn't contain a break statement, the else clause will always be executed.

Upvotes: 2

Mark Hildreth
Mark Hildreth

Reputation: 43071

Not sure if you're not understanding the indentation (or lack thereof) on the else statement, or the fact that there is an "else" on the for loop. If the former case...

The formatting is valid because print >> out is a "simple statement".

Here is the grammar for a for statement:

for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

Notice that after the colon in the optional "else" block, it wants a "suite", the grammar of which is...

suite         ::=  stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
statement     ::=  stmt_list NEWLINE | compound_stmt
stmt_list     ::=  simple_stmt (";" simple_stmt)* [";"]

So, it's possible in python to create a list of simple statements as an alternative to a block of statements. This is also valid...

for i in sorted(indexes, key=lambda x: indexes[x]['name']):
    pct = indexes[i]['count'] and indexes[i]['count']/clusters_sum*100 or 0
    if pct < 0.06: continue
    print >> out, '%8s  %9d  %5.1f' % (indexes[i]['name'], indexes[i]['count'], pct)
else: print >> out; print >> out; print >> out

and would be equivalent to...

for i in sorted(indexes, key=lambda x: indexes[x]['name']):
    pct = indexes[i]['count'] and indexes[i]['count']/clusters_sum*100 or 0
    if pct < 0.06: continue
    print >> out, '%8s  %9d  %5.1f' % (indexes[i]['name'], indexes[i]['count'], pct)
else:
    print >> out
    print >> out
    print >> out

However, I think most people would prefer seeing the second syntax.

Upvotes: 2

Andrew Clark
Andrew Clark

Reputation: 208475

See the documentation on else clauses on loops, this is valid syntax and the code within the else block is executed as long as there was no break, return, or uncaught exception within the loop.

In this particular case the else clause will always be executed since none of the above conditions (other than an exception) can happen, so it is equivalent to the following:

    for l in range(1,9):
        indexes = pickle.load(open('%s_%d.pkl'%(fc,l)))

        clusters_sum = sum([indexes[i]['count'] for i in indexes])
        print >> out, 'Lane %d: %d clusters PF.\n%8s  %9s  %5s' % (l,clusters_sum,'Index','Count','%')
        for i in sorted(indexes, key=lambda x: indexes[x]['name']):
            pct = indexes[i]['count'] and indexes[i]['count']/clusters_sum*100 or 0
            if pct < 0.06: continue
            print >> out, '%8s  %9d  %5.1f' % (indexes[i]['name'], indexes[i]['count'], pct)
        
        print >> out

Upvotes: 6

Related Questions