12

I know there are many questions on tabs vs. spaces, but it appears that, contrary to what PEP 0008 says about Python 3, mixing tabs and spaces is not always illegal. Specifically, mixing tabs and spaces in the same block is illegal, but blocks with spaces and blocks with tabs are allowed in the same file.

For example, this throws a TabError on Python 3.4:

for x in range(10):
    print(x)  # Spaces
    print(x)  # Tab

But this runs fine:

for x in range(10):
    print(x)  # Spaces

for y in range(5):
    print(y)  # Tab

Is this by design?

Edit: The question is not whether tabs are better than spaces. The question is whether Python's allowing tabs and spaces in the same file is by design.

2 Answers 2

10

The test for this is pretty simple (Lib/tests/test_exceptions.py):

    self.raise_catch(TabError, "TabError")
    try: compile("try:\n\t1/0\n    \t1/0\nfinally:\n pass\n",
                 '<string>', 'exec')
    except TabError: pass
    else: self.fail("TabError not raised")

Looking at the code where this error is actually thrown (Parser/tokenizer.c, tok_get()) it looks like this merely compares the indentation kind to what the previous line used, and not what is used throughout the file.

The documentation says (Doc/reference/lexical_analysis.rst, emphasis mine)

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.

It's okay to mix tabs and spaces if the "blocks" are completely "separated" by going back to indentation level 0; as there can be no confusion about the program's logic due to tab width settings. The problem with mixing tabs and spaces in Python is that Python assumes that a tab is eight spaces wide, but that the programmer's editor may use something else. For example, code like this:

def my_fun(i):
    if i == 6:
        foo()
------->bar()  # Tab

Will be seen as this with a tabstop of 4:

def my_fun(i):
    if i == 6:
        foo()
    bar()

Which is obviously not what the program does!

But in cases like:

def my_fun(i):
    if i == 6:
        foo()
        bar()

def my_fun2(i):
--->if i == 7:
--->--->foo()
--->--->bar()

It's okay from a "logic" point of view as no matter how I view tabs, it's always clear what the logic is. It's of course still a bad idea to mix tabs and spaces in a single file, but that's merely a stylistic error, and not a logic error ;-)

So to answer the question: judging from that one line in the documentation, I would say that this is by design. I can't find a PEP for this, though, and this case isn't tested. I would be not rely on it that all Python versions in the future behave the same!

1

Python tries to segment each little block of code so that when you copy and paste, it still works, and you aren't forced to make everything perfect. One of the many beauties of python.

PEP 8 is just a convention for the most readable code, and I recommend that you do follow it, but you don't have to

If you want to look for what PEP 8 encompasses there are several editors that will inspect your code for violations that are legal in python, but not nice. I use PyCharm. PyCharm doesn't like when you use spaces and tabs in the same file and it will get snarky with the squiggle under-linings.

1
  • I'm not sure if I understand what you mean with "tries to segment each little block of code"? Commented Mar 17, 2016 at 15:43

Not the answer you're looking for? Browse other questions tagged or ask your own question.