My misunderstanding about tabs in Python 3

Python 2 is famously relaxed about mixing tabs and spaces in Python code, although at the same time I believe it rigidly assumes that tabs are always at 8-space intervals (some editors offer you options here). When people used 8-space indent levels this wasn't too big of an issue, but it became one as the Python style moved to 4-space indents, because then some indents could be pure tabs but others had to involve spaces. Python 3 famously stopped being so relaxed, but for years I vaguely misunderstood how and thought it was more or less required to indent Python 3 code with spaces only.

(This belief wouldn't have survived if I actually thought about it, because I've converted historical Python 2 code that used tabs for indentation to Python 3 code with minor syntax changes and a change in the '#!' line. This definitely wouldn't have worked if Python 3 didn't still accept tabs.)

The official rules are described in the language reference in 2.1.8 Indentation . The documentation phrases it as:

Indentation is rejected as inconsistent if a source file mixes tabs and spaces in a way that makes the meaning dependent on the worth of a tab in spaces; a TabError is raised in that case.

If I'm understanding it correctly this time around, this means that you can have spaces after tabs, but you can't sometimes have tabs at the start and sometimes have the equivalent amount of spaces (well, equivalent in an 8-space tab world). The effect of this is that if you have some lines indented with tabs at the start or some lines indented by spaces only, you must indent all lines that way.

Where this comes up for me is when I'm editing existing code and for one reason or another my editor isn't set right. In GNU Emacs, this typically means that I wound up with indent-tabs-mode set wrong ( perhaps my code for automatically determining the right setting didn't run ). In Vi(m), this typically means I'm editing a Python 3 program written with spaces based indentation and I used the TAB key when adding a new line (which inserts an actual tab character for me). Sadly this somewhat discourages me from using Vim to edit Python 3 code.

In theory I could fix this as a one time thing by converting from tabs to spaces any time I touch a file. Vim makes this very easy, as I can simply run the entire file through ' expand ' (with the ' :! ' command), and I can go the other way with ' unexpand '. GNU Emacs similarly has ' untabify ' and ' tabify ' commands (which I'm noting down here partly so I can find them later).

In practice this isn't likely to happen. I'm somewhat stubborn, sometimes it would be a bunch of work due to how many files are involved, and I don't want to yank around code and create a big mystery diff in the code's version control history. The time to do such a major conversion might have been as part of the Python 2 to Python 3 change (although as a separate commit from the meaningful changes), perhaps at the same time as changing from 8-space indents to 4-space indents. But generally that ship has sailed now.

(Keeping code tab-based has the quiet advantage that co-workers using plain vi(m) are more likely to be able to make successful spot changes to the code. If I dutifully convert it all to space-based indentation, hitting TAB in vi(m) is a trap.)

( 2 comments .)