Default indentation of 4 columns

Tim Peters tim_one at email.msn.com
Sun Oct 24 23:31:39 EDT 1999


[François Pinard]
> ... I'm reasonably trying to follow Guido's style guide,

    http://www.python.org/doc/essays/styleguide.html

> somewhat helped in doing so by the nice Emacs Python mode.
>
> The only thing that really rebukes me is the interdiction to use
> capitals in comments to mark non-terminals (or variables), as it
> does not get accompanied by a better suggestion, or at least, none
> yielding as much clarity.

<GUIDOQUOTE>
It is best to list each argument on a separate line, with two dashes
separating the name from the description, like this:

def complex(real=0.0, imag=0.0):
    """Form a complex number.

    Keyword arguments:
    real -- the real part (default 0.0)
    imag -- the imaginary part (default 0.0)

    """
    if imag == 0.0 and real == 0.0: return complex_zero
    ...
</GUIDOQUOTE>

That's certainly clear!  The first line of the docstring doesn't help,
though.  This has begun to matter (to me, and hence it should now matter to
everyone <wink>) in the current CVS versions of IDLE and PythonWin, where
Mark Hammond's calltips extension pops up a little window containing the
first line of the docstring as you're typing a function/method call.  I've
been playing with simply repeating the arglist in the docstring's first
line, as in

def complex(real=0.0, imag=0.0):
    """real=0., imag=0. -> return a complex number.

    Keyword arg "real" (default 0.) gives the real part of the result.
    Keyword arg "imag" (default 0.) gives the imaginary part of the result.
    """

    if imag == 0.0 and real == 0.0: return complex_zero
    ...

This is working out kinda OK; for methods I omit mentioning the "self"
argument; horizontal space is precious in that first line, though, and it's
already irksome in cases like e.g.

def divide(numerator, denominator):
    """numerator, denominator -> return numerator divided by denominator."""
    ...

> The 4 columns indentation rule is quite acceptable on average, expect when
> I have things like, say:
>
>     for file_name, line_number, function_name, python_text in frames:
>         if (function_name[0] not in ('_', '<')
>             and function_name not in transparent_functions):
>             name = os.path.basename(file_name)
>             if name not in transparent_files:
>                 return name, line_number

Ah!  You read what Guido wrote but not what he meant:  to think like Guido
here is to think like the Python parser, and to the latter the indentation
of a continued line is irrelevant (it generates neither INDENT nor DEDENT
tokens, so, despite what you *see* <wink>, isn't really indentation at all).

<GUIDOQUOTE screaming_added_by="tim">
The preferred way of wrapping long lines is by using Python's implied line
continuation inside parentheses, brackets and braces. If necessary, you can
add an extra pair of parentheses around an expression, but sometimes using a
backslash looks better. MAKE SURE TO INDENT THE CONTINUED LINE
APPROPRIATELY. Emacs Python-mode does this right. Some examples:

class Rectangle(Blob):

    def __init__(self, width, height,
                 color='black', emphasis=None, highlight=0):
        if width == 0 and height == 0 and \
           color == 'red' and emphasis == 'strong' or \
           highlight > 100:
            raise ValueError, "sorry, you lose"
        if width == 0 and height == 0 and (color == 'red' or
                                           emphasis is None):
            raise ValueError, "I don't think so"
        Blob.__init__(self, widt, height,
                      color, emphasis, highlight)
</GUIDOQUOTE>

There is no case in the above where a continued line follows the "4-column
indent" rule; that rule doesn't apply because-- again, from the True Python
View --a continued line is not (despite mundane appearances) indented at
all.

As to what virtual <wink> indentation *is* "appropriate" for a continued
line, the appeal to pymode is normative but unhelpful:  pymode's indentation
heuristics are complex.  For the most part, they're faithfully mimicked in
the current CVS version of IDLE, so if you want to reverse-engineer them
from Python code instead of elisp, IDLE is the place to look.

But easier to remember that readability is the goal.  I'd write your example
as

    for file_name, line_number, function_name, python_text in frames:
        if (function_name[0] not in ('_', '<') and
                function_name not in transparent_functions):
            name = os.path.basename(file_name)
            ...

or

    for file_name, line_number, function_name, python_text in frames:
        if function_name[0] not in ('_', '<') and \
              function_name not in transparent_functions:
            name = os.path.basename(file_name)
            ...

or

    for file_name, line_number, function_name, python_text in frames:
        if (function_name[0] not in ('_', '<') and
            function_name not in transparent_functions
           ):
            name = os.path.basename(file_name)
            ...

or

    for file_name, line_number, function_name, python_text in frames:
        if (    function_name[0] not in ('_', '<') and
                function_name not in transparent_functions):
            name = os.path.basename(file_name)
            ...

or whatever looks good at the moment, depending on the day's drug of choice
<wink>.

pymode and (the current CVS) IDLE *suggest* your original indentation *not*
because of the 4-column indent rule, but because when a line is continued by
virtue of an unclosed bracketing structure ([], () or {}), it tries to line
it up with the first non-whitespace character following the open bracket of
the closest-containing unclosed bracketing structure.  For example, all the
indents here are what pymode/IDLE/PythonWin suggest:

if (      blah1 and
          blah2 and
          blah3):
    xxx

It's sheer coincidence in your example that the first non-whitespace
character following the open paren was 4 columns to the right of the 'i' in
"if", and I agree it doesn't read well.  So hit the spacebar a few times --
pymode won't hit you!

even-if-guido-would-like-it-to<wink>-ly y'rs  - tim






More information about the Python-list mailing list