Keeping to 79 char line limit in Python with multiple indents
Question: I understand that to write good Python code, I should keep my lines to no more
than 79 characters.

This is fine most of the time, but if I have various nested for loops and if
statements themselves nested within a class, I might easily find that I have 5
or 6 indents (ie 20-24 characters, if I'm indenting by 4 spaces a time) before
I start. Then the 79 character limit becomes quite tricky. I'm aware of
various tricks like implicit continuations within brackets and using brackets
to concatenate long strings, but even so, it gets a bit fiddly.

So, what do you gurus advise?

Indenting by 2 spaces instead of 4 would help, but is that considered good
style? Not sure it would help make my code more readable, and I note that PEP8
says to use 4 spaces.

If I find I have multiple levels of indents, is that perhaps I sign that I'm
writing bad code? And if so, any helpful tips or tricks for ways to avoid too
much nesting?

Am I right in trying to stick to the 79 character recommendation in the first
place?

Or do I just have to get used to a lot of statements broken over multiple
lines?

Thanks Adam


Answer: ### 1\. Loops

You can often use
[`itertools.product`](http://docs.python.org/3/library/itertools.html#itertools.product)
or
[`itertools.combinations`](http://docs.python.org/3/library/itertools.html#itertools.combinations)
to transform nested loops to a single loop.

When the loops are independent, use `product`. For example, these nested
loops:

    
    
    for x in range(3):
        for y in range(5):
            for z in range(7):
                print((x, y, z))
    

become the single loop:

    
    
    from itertools import product
    for x, y, z in product(range(3), range(5), range(7)):
        print((x, y, z))
    

When the loop indices must be distinct, then you can use `combinations`. For
example, these nested loops:

    
    
    for start in range(length - 1):
        for end in range(start + 1, length):
            print((start, end))
    

become the single loop:

    
    
    from itertools import combinations
    for start, end in combinations(range(length), 2):
        print((start, end))
    

See [here](http://codereview.stackexchange.com/a/31872/11728) for a real-life
example using `product`, and
[here](http://codereview.stackexchange.com/a/18659/11728) for an example using
`combinations`.

### 2\. Conditions

When you have lots of `if` statements, it's often possible to reorganize the
code to save indentation steps, and at the same time make the code clearer.
The basic idea is to dispose of errors first, and then cases in which you can
`return` immediately, so that the main body of the condition doesn't need to
be indented so far (or, in many cases, at all). For example, if you have code
like:

    
    
    if x >= 0:
        if x == 0:
            return 1
        else:
            # ... main body here ...
            return result
    else:
        raise ValueError("Negative values not supported: {!r}".format(x))
    

Then you can reorganize the code like this:

    
    
    if x < 0:
        raise ValueError("Negative values not supported: {!r}".format(x))
    if x == 0:
        return 1
    # ... main body here ...
    return result
    

which saves you two levels of indentation for the main body.

