
Python: Myths about Indentation - shawndumas
http://www.secnetix.de/olli/Python/block_indentation.hawk
======
parfe
Python white space indentations adds some overhead when pasting code but
overall I feel improves the code I write and the code I have to read. I think
if it were possible to do multiline anonymous functions a lot of the feel of
python would change and there would be a lot more function calling with nested
anonymous blocks. I don't know if that would be an improvement or not, but I
personally like my coworkers (and me) being forced to have a binding to the
code they are writing in the block they are writing it in.

The adverse visceral reaction to white space (which I think is akin to the
reaction to parens in lisp) appears to me to be people being unhappy with
being "forced" to do something. These (for me) happen to be the same people
who don't understand why the code they wrote in their personal (and ever
fluid) style is no good to be added to our code base.

~~~
gbog
> overhead when pasting code

No sure I get what you mean. I pasted a lot of code in PHP and Python, and in
both case you have to select the pasted block and adjust left or right
according to the change of depth level.

> people being unhappy with being "forced" to [indent]

Well, then why the Hell would these people be happy to be forced to write {
and } around their blocks?

For me, there is one little annoyance with indent as syntax in Python, it is
that it is harder for my editor (Vim) to let me jump from def to the end of
the function, and the reverse. (Or there is a conf, a plugin I missed? I know
about indent folding, but I just want % to behave like if I had curlies.)

~~~
parfe
>I pasted a lot of code in PHP and Python, and in both case you have to select
the pasted block and adjust left or right according to the change of depth
level.

Yes, you readjust the PHP for aesthetics. Not for correctness of execution.

In vim, if I recall(emacs for a while now), =G auto formats bracketed code
without issue. Pasting code, deleting enclosing block, adding an enclosing
block, or highlighting a mismatched bracket (when formatting goes horribly
wrong) can be handled automatically.

~~~
gbog
> Yes, you readjust the PHP for aesthetics

Here we differ. A code uncorrectly indented is wrong for me, and must be
corrected right now. I don't care at all if it runs or not.

~~~
parfe

        if user_set_delete:
            logger.info("User set flag to delete file")
        delete_file()
    

vs

    
    
        if($user_set_delete===True){
            log("User set flag to delete file");
        delete_file();
        }
    
    

"Correct" and "looks good" can have very different consequences. Acting like
proper indentation for looks is on the same level as proper indentation for
execution is ignoring the real dangers of improperly indented python.

I know copying that php block will not change the execution, no matter how it
is formatted vs copying python where I need to guarantee I've got it right.
Hence "some overhead".

~~~
headhuntermdk
Actually

    
    
      if user_set.delete:
          logger.info("User set flag to delete file")
      delete_file()
    

Becomes:

    
    
      if ($user_set_delete==True){
          log("user set flag to delete file")
      }
    
      delete_file();

~~~
pyre
The point being that when the indentation gets screwed up via the
copy/pasting, the if changes the meaning of the code vs just changing the
aesthetics.

------
LeafStorm
One nice thing about significant indentation is that it forces new programmers
to learn how to indent their code properly. I'm taking an Intro to Java course
now (in retrospect, I should have tried to place out), and most of the
students in the class have absolutely terrible indentation.

The only major downside of significant indentation is that it makes it
impossible to define multi-line anonymous functions in a clean way.

~~~
gbog
> multi-line anonymous functions

This is maybe a bit far from the topic, but I would like to know why there is
such a need for anonymous functions in Python.

I understand very well the need for stateless functions (functions that do not
change anything else than their return value, have no side effect, except
maybe logging), and I understood it was a piece of functional programming.

In Javascript, with silent overwriting of functions and without modules, it is
obviously very bad to pollute the only namespace with function names that can
clash with each other, but in Python, you are or should be always inside a
relatively small scope, and there you can def _my_temp_func() without any
problems, no?

Moreover, as it is lame to use _temp as function name, it forces you to
formulate a meaningful function name, which is good pratice, especially for
your lectorate, right?

Or am I missing something?

~~~
masklinn
> This is maybe a bit far from the topic, but I would like to know why there
> is such a need for anonymous functions in Python.

Building new control structures in-language, without having to hack the
interpreter, and without the result looking like somebody has puked all over
your screen. First-class functions are under-used in Python because they're
syntactically and semantically heavy. With full anonymous functions, the
`with` statement would not have been needed, it could have been handled
through a higher-order function, akin to Haskell's `bracket`[0]

> In Javascript, with silent overwriting of functions and without modules, it
> is obviously very bad to pollute the only namespace with function names that
> can clash with each other

Namespace pollution is completely irrelevant (it's very easy to handle it in
Javascript via the namespace pattern).

> Moreover, as it is lame to use _temp as function name, it forces you to
> formulate a meaningful function name, which is good pratice, especially for
> your lectorate, right?

If it is, why can I put name-less blocks of code in `for`, `if`, `while` and
`with` bodies?

Not all code blocks need a name. Those that do will be given one.

[0]
[http://hackage.haskell.org/packages/archive/base/latest/doc/...](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-
Exception-Base.html#v:bracket)

~~~
thurn
In fact, Haskell style frowns on using too many lambdas. It's generally felt
that adding named functions is better for debugging and readability, the same
as in python. So with the bracket function, for example, it's still considered
better practice to pass named functions to it.

~~~
masklinn
> In fact, Haskell style frowns on using too many lambdas. It's generally felt
> that adding named functions is better for debugging and readability, the
> same as in python

That's really besides my point. And last time I checked, Haskell's `if` and
`case` expressions did not take functions, they took anonymous expressions.

> So with the bracket function, for example, it's still considered better
> practice to pass named functions to it.

To pass a named function as third argument to bracket?

------
mcantor
This is the main point:

"So the conclusion is: Python forces you to use indentation that you would
have used anyway, unless you wanted to obfuscate the structure of the
program."

You _were_ going to use consistent indentation anyway, _right_?

------
Thrymr
It seems to me all the resistance from people who don't like Python's
meaningful indentation is from people who haven't coded in Python. It seemed
weird to me at first, too, but really, it takes about an hour of actually
using code to think, "Hey, this just lets me get rid of all the ugly brackets,
and you don't lose anything by having to write it this way!" I don't even
think you have to love Python as a whole to get the fact that this part of it
is simple and elegant.

~~~
njharman
I can attest to this being one of the people who resisted until I actually
used the language. Now I absolutely can't stand languages without significant
indentation. "why is this retarded language forcing me to manually end blocks
when it's bloody obvious from indentation!!!"

------
vessenes
Python's indentation rules as specced originally are considered too loose by
most Python programmers, hence PEP8 -- specifying spaces only, and a host of
readability rules.

Consider that the competing scripting language at launch was Perl.

Now consider the benefit to a large team of well formatted easy to read code;
Python's whitespace and indentation rules are there to enhance maintanability
and readability, and they generally work.

As the article shows, you CAN make python look worse, but you shouldn't.

Incidentally, languages like Google Go take this one farther and embed
deterministic formatting as a part of the language toolkit. This is brilliant.
I would like to see such a thing incorporated into Python as well.. (Where's
my backlist of to-do items?)

------
phzbOx
I'm an avid python user and a big problem I have is that you can't finish a
line with '.' and continue on the next line. For instance:

    
    
      some_object.
        do_something(..).
        do_something_else(..).
    

Doesn't work. It needs to be written:

    
    
      some_object.\
        do_something().\
        do_something_else()
    

or

    
    
      some_object\
        .do_something()\
        .do_something_else()
    

It's ok to write \ a couple of time, but I feel like it makes chain-able
functional methods really ugly to use because of that.

~~~
pyre
You don't need to escape line endings within parens:

    
    
      (someobject
         .do_something()
         .do_something())

~~~
phzbOx
Yeah. That's the hack I use, but it makes it a bit no pythonic.

~~~
pyre
From what I gather, the Pythonic way to write that would be:

    
    
      some_object.do_something().do_something()\
        .do_something().last_thing()
    

Basically, go to the end of the line and wrap with an indent. That's the way
that I see most function calls with a long list of arguments in Python. In
Perl, you might see something like:

    
    
       GetOptions(
         'h|help' => \my $help
       );
    

Whereas in Python you would see:

    
    
      parser.add_option('-h','--help',meta="HELP",target="HELP",
          help="Print help message",action="store_true",default=False)

------
chaostheory
Question: why don't pythonistas use tabs instead of spaces for indentation? To
my knowledge pretty much every editor can be customized to display tabs in
whatever length users want e.g. 2 spaces, 4 spaces, etc... imo it's a lot
easier than dealing with different sets of code with a varying number of
spaces for indentation.

~~~
veyron
tabs are interpreted as exactly 8 spaces, and oftentimes people set editors to
use less than 8 spaces

~~~
burgerbrain
Why does it matter to you if people set their editors that way? What is your
point here?

~~~
ominous_prime
The standard indentation is 4 spaces, and people often have their tabwidth set
to 4 spaces. Sometimes tabbed code (often older code, before spaces were
really standard), end up with mixed tabs and spaces. The logic of the code
then reads completely differently depending on your editor settings.

~~~
burgerbrain
I'm not advocating people mix tabs and spaces, I'm advocating that people
always use tabs so that others can display it as they wish.

~~~
Peaker
If you use tabs everywhere, your code alignment will be all wrong:

    
    
      if x:
      ----some_long_func_name(...,
      ----                    blah...
    

Note that ---- is indentation and the spaces need to be _spaces_. If you use
tabs for all of this, it will come out misaligned.

You could say -- then why not use tabs for the indent part, and spaces for the
alignment part? Because virtually no editors support doing this automatically
(and doing this manually is not practical). The few editors that do support
automating this, don't make it discoverable (let alone a default).

What you end up with is a horrible mixture of tabs and spaces, or if you use
tabs only, then code that does not align right.

Using tabs _simply does not work in practice_. Spaces may have the (supposed)
disadvantage of a fixed indentation size, but they really are the only way to
make indented code work across different editors. And this is not an optional
thing, therefore tabs should be banned, completely.

~~~
Goladus
Technically that's incorrect. A parameter list has an implicit line
continuation so the 4 spaces aren't necessary.

    
    
        if x:
        ----some_long_func_name(...,
                                blah...)
        ----fn2(x)
        else:
        ----fn3()
    

However, I do agree that using tabs in python quickly becomes an enormous
headache.

~~~
Peaker
My point was not that the code becomes incorrect -- but that the point of
indentation is to make code readable, and it is lost when using tabs because
the only correct use of tabs for indentation is not well supported by editors
in practice.

------
veyron
Myth: "You cannot safely mix tabs and spaces in Python."

In fact, you can mix 8 tabs with spaces in CPython (and do wacky stuff like

def f():

<tab><8 spaces>x=3

<4 spaces><tab><4 spaces>y=3

<8 spaces><tab>return x+y

~~~
andrewaylett
You can, yes, but is it _safe_?

My understanding of the article is that you shouldn't do it, because it's
liable to cause confusion -- it's not safe.

~~~
koenigdavidmj
In Python 2, you can run tabnanny[1]. In Python 3, I do not believe that
unambiguous tab mixing is allowed.

1: <http://docs.python.org/library/tabnanny.html>

------
onedognight
> "You cannot safely mix tabs and spaces in Python."

You _can_ mix spaces and tabs all you want as long as you are consistent. This
is fine.

    
    
        if 0:
        <tab><sp><tab><sp>1
        <tab><sp><tab><sp>2
    

This is not, for any number of spaces.

    
    
        if 0:
        <tab>1
        <sp><sp><sp><sp><sp><sp><sp><sp>2

~~~
falcolas
Technically, the parser converts one tab to 8 spaces (at least in the versions
of python I'm familiar with), so your second statement is not quite true.

def foo(): <tab>print 'a' <sp><sp><sp><sp><sp><sp><sp><sp>print 'b'

compiles and runs properly in python 2.6.

------
jarin
I don't really have a problem with Python per se, but the one thing that bugs
me is that the significance of indentation encourages the use of 4 or 8 space
indents. I guess on one hand it's good because it would probably discourage
heavy nesting, but seems like it would be a pain to paste on blogs and would
require a lot more eye movement.

I guess you probably just get used to it, I'm just coming from the 2 space
Ruby standard.

------
pyre
I will say that the person I know with the most visceral reaction to Python's
indentation rules writes code like this:

    
    
      sub func { shift->func1(shift)->func2(@_) }
     
      sub things_with_attr { grep { $_[0]->is_attr_true($_) } $_[0]->things }
    

Only the function names have been obscured.

