Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 3 allows mixing spaces and tabs?

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.

like image 722
Pedro Avatar asked Mar 17 '16 14:03

Pedro


People also ask

Can you mix tabs and spaces in Python?

Never mix tabs and spaces. The most popular way of indenting Python is with spaces only. The second-most popular way is with tabs only. Code indented with a mixture of tabs and spaces should be converted to using spaces exclusively.

Does Python use tabs or spaces?

Tabs or Spaces? Spaces are the preferred indentation method. Tabs should be used solely to remain consistent with code that is already indented with tabs. Python disallows mixing tabs and spaces for indentation.

What are tabs used for in Python?

The Python tab provides auto-completion so that you can quickly finish statement tokens. If you write a partial token but are unsure how to complete it or want to fill in the token automatically, press Tab while the cursor is still in the input pane.

What are invisible space and tabs called in Python?

Indentation in Python refers to the (spaces and tabs) that are used at the beginning of a statement. The statements with the same indentation belong to the same group called a suite. Consider the example of a correctly indented Python code statement mentioned below.


1 Answers

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!

like image 102
Martin Tournoij Avatar answered Nov 15 '22 17:11

Martin Tournoij