According to the Zen of Python, "There should be one — and preferably only one — obvious way to do it." Also, "simple is better than complex." By these criteria, Python's PEP8 indentation rules are unpythonic.
First, there is a choice of using a so-called hanging indent
def long_function_name( var_one, var_two, var_three, var_four): print(var_one)
or of aligning with the opening parenthesis
def long_function_name(var_one, var_two, var_three, var_four)
With the latter, what if the name of the function changes? Perhaps you have an editor that automatically reindents the following lines to maintain alignment, or you run all your code through a formatter — but why should that be necessary?
The latter choice would also means allowing
if (this_is_one_thing and that_is_another_thing): do_something()
even though the length of the "if (" coincides with that of the indentation unit. so that the indentation fails to distinguish the line on which the nested statements begin. And so PEP8 has to treat this as a special case
if (this_is_one_thing and that_is_another_thing): do_something()
But in cases other than an 'if' statement, unless a line break is added after the '(', that's not allowed.
Then there is the choice that PEP8 offers between
my_list = [ 1, 2, 3, 4, 5, 6, ] result = some_function_that_takes_arguments( 'a', 'b', 'c', 'd', 'e', 'f', )
and
my_list = [ 1, 2, 3, 4, 5, 6, ] result = some_function_that_takes_arguments( 'a', 'b', 'c', 'd', 'e', 'f', )
The second option entails adding another special case to the rules, i.e., treating closing parentheses differently from other code. There is not even any particularly compelling reason for giving the closing square or round bracket a line of its own.
PEP8 indentation rules even allow for continuation lines to be indented by fewer than four spaces.
Choice is appealing, but short and simple rules are what give real freedom. It's because all drivers must stop at every red light that we can all get across town relatively quickly. The PEP8 rules, in contrast, invite questions and discussion and time spent deciding between the relative importance of personal preferences and consistency with existing code.
Here then, I submit, is the one obvious way to do it:
That's all.
Here's how it looks:
def long_function_name(var_one, var_two, var_three, var_four): my_list = [ 1, 2, 3, 4, 5, 6] nest_dict = { a: [ (1, 'a'), (2, 'b'), ], b: [ (3, 'c'), (4, 'd'), ]} if (var_one > len(my_list) and nest_dict[a][0] == 1): do_something() print var_one result = some_function('a', 'b', 'c', 'd', 'e', 'f')
That example is not PEP8-compliant, but you're free to add line breaks to satisfy PEP8's "When using a hanging indent ... there should be no arguments on the first line". The pep8 checker will also complain about the lack of indentation for the nested data structure — though in fact PEP8 itself says nothing about intra-statement indentation. If you prefer to liberalize the above rules to include indentation for data structures, you can satisfy the pep8 tool (at least version 1.6.2) with code like
def long_function_name( var_one, var_two, var_three, var_four): my_list = [ 1, 2, 3, 4, 5, 6] nest_dict = { a: [ (1, 'a'), (2, 'b'), ], b: [ (3, 'c'), (4, 'd'), ]} if (var_one > len(my_list) and nest_dict[a][0] == 1): do_something() print var_one result = some_function( 'a', 'b', 'c', 'd', 'e', 'f')
For pylint, on the other hand, that's still not enough: it will tut-tut loudly at the universal eight-space indentation for continuation lines. To silence it, I suggest simply disabling 'bad-continuation' in your pylintrc.
Update: The Principle of Orthogonal Program Code Indentation which informs the above convention is now described separately.
— Michael Breen, 2017