The test for this is quite 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 in which this error is actually called ( Parser/tokenizer.c
, tok_get()
), it looks like it just compares the type of indentation with what was used by the previous line, rather than what is used throughout the file.
The documentation says ( Doc/reference/lexical_analysis.rst
, my emphasis)
Indentation is rejected as inconsistent if the source file mixes the tabs and spaces so that the value depends on the value of the bookmark in spaces ; a TabError
occurs in this case.
It is possible to mix tabs and spaces if the "blocks" are completely "divided", returning to the indent level of 0; since there can be no confusion regarding the program logic due to the tab width settings. The problem with mixing tabs and spaces in Python is that Python assumes the tab is eight spaces wide, but the programmerโs editor might use something else. For example, the code is as follows:
def my_fun(i): if i == 6: foo() ------->bar()
Will be considered like this with tabost 4:
def my_fun(i): if i == 6: foo() bar()
This is clearly not what the program does!
But in such cases as:
def my_fun(i): if i == 6: foo() bar() def my_fun2(i): --->if i == 7: --->--->foo() --->--->bar()
Everything is in order from a logical point of view, no matter how I look at the tabs, it is always clear what logic is. Of course, itโs still a bad idea to mix tabs and spaces in one file, but this is just a stylistic mistake, not a logical mistake; -)
So, to answer the question: judging by this one line in the documentation, I will say that this is by design. However, I cannot find the PEP for this, and this case has not been verified. I would not rely on this that all versions of Python in the future behave the same!