Why does indentation matter?
In Python, indentation is used to delimit blocks of code. This is different from many other languages that use curly braces {} to delimit blocks such as Java, Javascript, and C. Because of this, Python users must pay close attention to when and how they indent their code because whitespace matters.
When Python encounters a problem with the indentation of your program, it either raises an exception called IndentationError or TabError.
A little history
The historical reasons for why Python uses indentation vs the arguably more commonly accepted curly braces {} is outlined in an article of the history of Python by Guido van Rossum — the creator of Python:
Python’s use of indentation comes directly from ABC, but this idea didn’t originate with ABC—it had already been promoted by Donald Knuth and was a well-known concept of programming style. (The occam programming language also used it.) However, ABC’s authors did invent the use of the colon that separates the lead-in clause from the indented block. After early user testing without the colon, it was discovered that the meaning of the indentation was unclear to beginners being taught the first steps of programming. The addition of the colon clarified it significantly: the colon somehow draws attention to what follows and ties the phrases before and after it together in just the right way.
How do I indent my code?
The basic rule for indenting Python code (considering that you treat the entire program as a «basic block») is: The first statement in a basic block, and each subsequent statement after it must be indented by the same amount.
So technically the following Python program is correct:
def perm(l):
# Compute the list of all permutations of l
if len(l) <= 1:
return [l]
r = []
for i in range(len(l)):
s = l[:i] + l[i+1:]
p = perm(s)
for x in p:
r.append(l[i:i+1] + x)
return r
However, as you can probably tell from above, randomly indenting your code makes is extremely hard to read and follow the flow of the program. It’s better to be consistent and follow a style.
PEP 8 — the Python style guide — says:
Use 4 spaces per indentation level.
That is, each statement that is starting a new block and each subsequent statement in the new block, should be indented four spaces from the current indentation level. Here is the above program indented according to the PEP8 style guide:
def perm(l):
# Compute the list of all permutations of l
if len(l) <= 1:
return [l]
r = []
for i in range(len(l)):
s = l[:i] + l[i+1:]
p = perm(s)
for x in p:
r.append(l[i:i+1] + x)
return r
Can I still use tabs?
Python realizes that some people still prefer tabs over spaces and that legacy code may use tabs rather than spaces, so it allows the use of tabs as indentation. PEP8 touches on this topic:
Spaces are the preferred indentation method.
Tabs should be used solely to remain consistent with code that is already indented with tabs.
Note however the one big caveat is not to use both tabs and spaces for indentation. Doing so can cause all kinds of strange hard to debug indentation errors. Python expands tabs to the next 8th column, but if your editor is set to a tab size of 4 columns, or you you use spaces as well as tabs, you can easily produce indented code that looks fine in your editor, but Python will refuse to run. The Python 3 compiler explicitly rejects any program containing an ambiguous mixture of tabs and spaces, usually by raising a TabError. However, by default, mixing tabs and spaces is still allowed in Python 2, but it is highly recommended not to use this «feature». Use the -t and -tt command line flags to force Python 2 to raise a warning or (preferably) an error respectively. PEP8 also discusses this topic:
Python 3 disallows mixing the use of tabs and spaces for indentation.
Python 2 code indented with a mixture of tabs and spaces should be converted to using spaces exclusively.
When invoking the Python 2 command line interpreter with the -t option, it issues warnings about code that illegally mixes tabs and spaces. When using -tt these warnings become errors. These options are highly recommended!
What does «IndentationError: unexpected indent» mean?
Problem
This error occurs when a statement is unnecessarily indented or its indentation does not match the indentation of former statements in the same block. For example, the first statement in the program below is unnecessarily indented:
>>> print('Hello') # this is indented
File "<stdin>", line 1
print('Hello') # this is indented
^
IndentationError: unexpected indent
In this example, the can_drive = True line in the if block does not match the indentation of any former statement:
>>> age = 10
>>> can_drive = None
>>>
>>> if age >= 18:
... print('You can drive')
... can_drive = True # incorrectly indented
File "<stdin>", line 3
can_drive = True # incorrectly indented
^
IndentationError: unexpected indent
Fix
The fix for this error is to first make sure the problematic line even needs to be indented. For example, the above example using print can be fixed simply be unindenting the line:
>>> print('Hello') # simply unindent the line
Hello
However, if you are sure the line does need to be indented, the indentation needs to match that of a former statement in the same block. In the second example above using if, we can fix the error by making sure the line with can_drive = True is indented at the same level as the former statements in the if body:
>>> age = 10
>>> can_drive = None
>>>
>>> if age >= 18:
... print('You can drive')
... can_drive = True # indent this line at the same level.
...
What does «IndentationError: expected an indented block» mean?
(This might also occur as SyntaxError: unexpected EOF while parsing in Python 3.8 or lower.)
Problem
This error occurs when Python sees the ‘header’ for a compound statement, such as if <condition>: or while <condition>: but the compound statement’s body or block is never defined. For example in the code below we began an if statement, but we never define a body for the statement:
>>> if True:
...
File "<stdin>", line 2
^
IndentationError: expected an indented block
In this second example, we began writing a for loop, but we forget to indent the for loop body. So Python still expects an indented block for the for loop body:
>>> names = ['sarah', 'lucy', 'michael']
>>> for name in names:
... print(name)
File "<stdin>", line 2
print(name)
^
IndentationError: expected an indented block
Comments don’t count as bodies:
>>> if True:
... # TODO
...
File "<stdin>", line 3
^
IndentationError: expected an indented block
Fix
The fix for this error is to simply include a body for the compound statement.
As shown above, a common mistake by new users is that they forget to indent the body. If this is the case, make sure each statement meant to be included in the compound statement’s body is indented at the same level under the compound statement’s beginning. Here is the above example fixed:
>>> names = ['sarah', 'lucy', 'michael']
>>> for name in names:
... print(name) # The for loop body is now correctly indented.
...
sarah
lucy
michael
Another common case is that, for some reason, a user may not want to define an actual body for the compound statement, or the body may be commented out. In this case, the pass statement can be used. The pass statement can be used anywhere Python expects one or more statements as a placeholder. From the documentation for pass:
pass is a null operation — when it is executed, nothing happens. It is useful as a placeholder when a statement is required syntactically, but no code needs to be executed, for example:
def f(arg): pass # a function that does nothing (yet) class C: pass # a class with no methods (yet)
Here is the above example with the if statement fixed by using the pass keyword:
>>> if True:
... pass # We don't want to define a body.
...
>>>
What does «IndentationError: unindent does not match any outer indentation level» mean?
Problem
This error occurs when you unindent a statement, but now the indentation level of that statement does not match that of any former statement. For example, in the below code we unindent the second call to print. However, the indentation level does not match that of any former statement:
>>> if True:
... if True:
... print('yes')
... print()
File "<stdin>", line 4
print()
^
IndentationError: unindent does not match any outer indentation level
This error is especially hard to catch because even one space will cause your code to fail.
Fix
The fix is to ensure that when you unindent a statement, the indentation level matches that of a former statement. Consider the above example once again. In the example, I want the second call to print to be in the first if statements body. So I need to make sure that that line’s indentation level matches that of the former statements in the first if statement’s body:
>>> if True:
... if True:
... print('yes')
... print() # indentation level now matches former statement's level.
...
yes
>>>
I’m still getting an IndentationError but my program appears to be correctly indented. What do I do?
If your program visually appears to have correct indentation, but your still getting an IndentationError you have most likely mixed tabs with spaces. This will sometimes cause Python to raises strange errors. See the subsection Special cases under What does «TabError: inconsistent use of tabs and spaces in indentation» mean? for an more in-depth explanation of the problem.
What does «TabError: inconsistent use of tabs and spaces in indentation» mean?
Problem
This error only occurs when you attempt to mix tabs and spaces as indentation characters. As said above, Python will not allow your program to contain a mix of tabs and spaces, and will raise the specific exception TabError if it finds you have. For example, in the program below, a mix of tabs and spaces is used for indentation:
>>> if True:
... if True:
... print()
... print()
... print()
File "<stdin>", line 5
print()
^
TabError: inconsistent use of tabs and spaces in indentation
Here is a picture which visually shows the whitespace in the above program. Gray dots are spaces, and gray arrows are tabs:
We can see we have indeed mixed spaces and tabs for indentation.
Special cases
Note Python will not always raise a TabError if you mix tabs and spaces into your program. If the program indentation is unambiguous, Python will allow tabs and spaces to be mixed. For example:
>>> if True:
... if True: # tab
... pass # tab, then 4 spaces
...
>>>
And sometimes Python simply chokes on the mixture of tabs and spaces and erroneously raises an IndentationError exception when a TabError would be more appropriate. Another example:
>>> if True:
... pass # tab
... pass # 4 spaces
File "<stdin>", line 3
pass # 4 spaces
^
IndentationError: unindent does not match any outer indentation level
As you can see, running your code this way can create mysterious errors. Even though the program visually appears to be fine, Python became confused trying to parse the tabs and spaces used for indention and errored out.
These are excellent examples that demonstrate why to never mix tabs and spaces and make use of the -t and -tt interpreter flags when using Python 2.
Fix
If your program is short, probably the easiest and quickest fix is to simply re-indent the program. Make sure each statement is indented by four spaces per indention level (see How do I indent my code?).
However, if you already have a large program that you’ve mixed tabs and spaces into, there are automated tools that can be used to convert all of your indentation to just spaces.
Many editors such as PyCharm and SublimeText have options to automatically convert tabs to spaces. There are also several on-line tools such as Tabs To Spaces or Browserling that allow you to quickly re-indent your code. There are also tools written in Python. autopep8 for example can automatically re-indent your code and fix other indentation errors as well.
Even the best tools though will sometimes not be able to fix all of your indentation errors and you’ll have to fix them manually. That’s why it’s important to always properly indent your code from the start.
A note about «SyntaxError» related indentation problems
Although not often, sometimes certain SyntaxError exceptions are raised due to incorrect indentation. For example, look at the code below:
if True:
pass
pass # oops! this statement should be indented!.
else:
pass
When the above code is run, a SyntaxError is raised:
Traceback (most recent call last):
File "python", line 4
else:
^
SyntaxError: invalid syntax
Although Python raises a SyntaxError, the real problem with the above code is that the second pass statement should be indented. Because the second pass isn’t indented, Python doesn’t realize that the previous if statement and the else statement are meant to be connected.
The fix for this type of error is to simply correctly re-indent your code. To see how to properly indent your code, see the section How do I indent my code?.
I’m still having a hard time with Python’s indentation syntax. What do I do?
Don’t get discouraged if you’re still struggling. It can take time to get use to
Python’s whitespace syntax rules. Here are some tips to help:
- Get an editor that will tell you when you have an indentation error. Some goods ones are as said above are, PyCharm, SublimeText, and Jupyter Notebook.
- When you indent your code, count out loud to yourself how many times you press the space-bar (or tab key). For example, if you needed to indent a line by four spaces, you would say out loud «one, two, three, four» while simultaneously pressing the space-bar each time. It sounds silly, but it helps train your brain to think about how deep you’re indenting your code.
- If you have an editor, see if it has an option to automatically convert tabs to spaces.
- View others’ code. Browse github or Stackoverflow and see examples of Python code.
- Just write code. That’s the single best way to get better. The more you write Python code, the better you’ll get.
Resources used
- https://en.wikipedia.org/
- https://docs.python.org/3/
- http://python-history.blogspot.com/2009/02/early-language-design-and-development.html
- https://www.python.org/dev/peps/pep-0008/
Why does indentation matter?
In Python, indentation is used to delimit blocks of code. This is different from many other languages that use curly braces {} to delimit blocks such as Java, Javascript, and C. Because of this, Python users must pay close attention to when and how they indent their code because whitespace matters.
When Python encounters a problem with the indentation of your program, it either raises an exception called IndentationError or TabError.
A little history
The historical reasons for why Python uses indentation vs the arguably more commonly accepted curly braces {} is outlined in an article of the history of Python by Guido van Rossum — the creator of Python:
Python’s use of indentation comes directly from ABC, but this idea didn’t originate with ABC—it had already been promoted by Donald Knuth and was a well-known concept of programming style. (The occam programming language also used it.) However, ABC’s authors did invent the use of the colon that separates the lead-in clause from the indented block. After early user testing without the colon, it was discovered that the meaning of the indentation was unclear to beginners being taught the first steps of programming. The addition of the colon clarified it significantly: the colon somehow draws attention to what follows and ties the phrases before and after it together in just the right way.
How do I indent my code?
The basic rule for indenting Python code (considering that you treat the entire program as a «basic block») is: The first statement in a basic block, and each subsequent statement after it must be indented by the same amount.
So technically the following Python program is correct:
def perm(l):
# Compute the list of all permutations of l
if len(l) <= 1:
return [l]
r = []
for i in range(len(l)):
s = l[:i] + l[i+1:]
p = perm(s)
for x in p:
r.append(l[i:i+1] + x)
return r
However, as you can probably tell from above, randomly indenting your code makes is extremely hard to read and follow the flow of the program. It’s better to be consistent and follow a style.
PEP 8 — the Python style guide — says:
Use 4 spaces per indentation level.
That is, each statement that is starting a new block and each subsequent statement in the new block, should be indented four spaces from the current indentation level. Here is the above program indented according to the PEP8 style guide:
def perm(l):
# Compute the list of all permutations of l
if len(l) <= 1:
return [l]
r = []
for i in range(len(l)):
s = l[:i] + l[i+1:]
p = perm(s)
for x in p:
r.append(l[i:i+1] + x)
return r
Can I still use tabs?
Python realizes that some people still prefer tabs over spaces and that legacy code may use tabs rather than spaces, so it allows the use of tabs as indentation. PEP8 touches on this topic:
Spaces are the preferred indentation method.
Tabs should be used solely to remain consistent with code that is already indented with tabs.
Note however the one big caveat is not to use both tabs and spaces for indentation. Doing so can cause all kinds of strange hard to debug indentation errors. Python expands tabs to the next 8th column, but if your editor is set to a tab size of 4 columns, or you you use spaces as well as tabs, you can easily produce indented code that looks fine in your editor, but Python will refuse to run. The Python 3 compiler explicitly rejects any program containing an ambiguous mixture of tabs and spaces, usually by raising a TabError. However, by default, mixing tabs and spaces is still allowed in Python 2, but it is highly recommended not to use this «feature». Use the -t and -tt command line flags to force Python 2 to raise a warning or (preferably) an error respectively. PEP8 also discusses this topic:
Python 3 disallows mixing the use of tabs and spaces for indentation.
Python 2 code indented with a mixture of tabs and spaces should be converted to using spaces exclusively.
When invoking the Python 2 command line interpreter with the -t option, it issues warnings about code that illegally mixes tabs and spaces. When using -tt these warnings become errors. These options are highly recommended!
What does «IndentationError: unexpected indent» mean?
Problem
This error occurs when a statement is unnecessarily indented or its indentation does not match the indentation of former statements in the same block. For example, the first statement in the program below is unnecessarily indented:
>>> print('Hello') # this is indented
File "<stdin>", line 1
print('Hello') # this is indented
^
IndentationError: unexpected indent
In this example, the can_drive = True line in the if block does not match the indentation of any former statement:
>>> age = 10
>>> can_drive = None
>>>
>>> if age >= 18:
... print('You can drive')
... can_drive = True # incorrectly indented
File "<stdin>", line 3
can_drive = True # incorrectly indented
^
IndentationError: unexpected indent
Fix
The fix for this error is to first make sure the problematic line even needs to be indented. For example, the above example using print can be fixed simply be unindenting the line:
>>> print('Hello') # simply unindent the line
Hello
However, if you are sure the line does need to be indented, the indentation needs to match that of a former statement in the same block. In the second example above using if, we can fix the error by making sure the line with can_drive = True is indented at the same level as the former statements in the if body:
>>> age = 10
>>> can_drive = None
>>>
>>> if age >= 18:
... print('You can drive')
... can_drive = True # indent this line at the same level.
...
What does «IndentationError: expected an indented block» mean?
(This might also occur as SyntaxError: unexpected EOF while parsing in Python 3.8 or lower.)
Problem
This error occurs when Python sees the ‘header’ for a compound statement, such as if <condition>: or while <condition>: but the compound statement’s body or block is never defined. For example in the code below we began an if statement, but we never define a body for the statement:
>>> if True:
...
File "<stdin>", line 2
^
IndentationError: expected an indented block
In this second example, we began writing a for loop, but we forget to indent the for loop body. So Python still expects an indented block for the for loop body:
>>> names = ['sarah', 'lucy', 'michael']
>>> for name in names:
... print(name)
File "<stdin>", line 2
print(name)
^
IndentationError: expected an indented block
Comments don’t count as bodies:
>>> if True:
... # TODO
...
File "<stdin>", line 3
^
IndentationError: expected an indented block
Fix
The fix for this error is to simply include a body for the compound statement.
As shown above, a common mistake by new users is that they forget to indent the body. If this is the case, make sure each statement meant to be included in the compound statement’s body is indented at the same level under the compound statement’s beginning. Here is the above example fixed:
>>> names = ['sarah', 'lucy', 'michael']
>>> for name in names:
... print(name) # The for loop body is now correctly indented.
...
sarah
lucy
michael
Another common case is that, for some reason, a user may not want to define an actual body for the compound statement, or the body may be commented out. In this case, the pass statement can be used. The pass statement can be used anywhere Python expects one or more statements as a placeholder. From the documentation for pass:
pass is a null operation — when it is executed, nothing happens. It is useful as a placeholder when a statement is required syntactically, but no code needs to be executed, for example:
def f(arg): pass # a function that does nothing (yet) class C: pass # a class with no methods (yet)
Here is the above example with the if statement fixed by using the pass keyword:
>>> if True:
... pass # We don't want to define a body.
...
>>>
What does «IndentationError: unindent does not match any outer indentation level» mean?
Problem
This error occurs when you unindent a statement, but now the indentation level of that statement does not match that of any former statement. For example, in the below code we unindent the second call to print. However, the indentation level does not match that of any former statement:
>>> if True:
... if True:
... print('yes')
... print()
File "<stdin>", line 4
print()
^
IndentationError: unindent does not match any outer indentation level
This error is especially hard to catch because even one space will cause your code to fail.
Fix
The fix is to ensure that when you unindent a statement, the indentation level matches that of a former statement. Consider the above example once again. In the example, I want the second call to print to be in the first if statements body. So I need to make sure that that line’s indentation level matches that of the former statements in the first if statement’s body:
>>> if True:
... if True:
... print('yes')
... print() # indentation level now matches former statement's level.
...
yes
>>>
I’m still getting an IndentationError but my program appears to be correctly indented. What do I do?
If your program visually appears to have correct indentation, but your still getting an IndentationError you have most likely mixed tabs with spaces. This will sometimes cause Python to raises strange errors. See the subsection Special cases under What does «TabError: inconsistent use of tabs and spaces in indentation» mean? for an more in-depth explanation of the problem.
What does «TabError: inconsistent use of tabs and spaces in indentation» mean?
Problem
This error only occurs when you attempt to mix tabs and spaces as indentation characters. As said above, Python will not allow your program to contain a mix of tabs and spaces, and will raise the specific exception TabError if it finds you have. For example, in the program below, a mix of tabs and spaces is used for indentation:
>>> if True:
... if True:
... print()
... print()
... print()
File "<stdin>", line 5
print()
^
TabError: inconsistent use of tabs and spaces in indentation
Here is a picture which visually shows the whitespace in the above program. Gray dots are spaces, and gray arrows are tabs:
We can see we have indeed mixed spaces and tabs for indentation.
Special cases
Note Python will not always raise a TabError if you mix tabs and spaces into your program. If the program indentation is unambiguous, Python will allow tabs and spaces to be mixed. For example:
>>> if True:
... if True: # tab
... pass # tab, then 4 spaces
...
>>>
And sometimes Python simply chokes on the mixture of tabs and spaces and erroneously raises an IndentationError exception when a TabError would be more appropriate. Another example:
>>> if True:
... pass # tab
... pass # 4 spaces
File "<stdin>", line 3
pass # 4 spaces
^
IndentationError: unindent does not match any outer indentation level
As you can see, running your code this way can create mysterious errors. Even though the program visually appears to be fine, Python became confused trying to parse the tabs and spaces used for indention and errored out.
These are excellent examples that demonstrate why to never mix tabs and spaces and make use of the -t and -tt interpreter flags when using Python 2.
Fix
If your program is short, probably the easiest and quickest fix is to simply re-indent the program. Make sure each statement is indented by four spaces per indention level (see How do I indent my code?).
However, if you already have a large program that you’ve mixed tabs and spaces into, there are automated tools that can be used to convert all of your indentation to just spaces.
Many editors such as PyCharm and SublimeText have options to automatically convert tabs to spaces. There are also several on-line tools such as Tabs To Spaces or Browserling that allow you to quickly re-indent your code. There are also tools written in Python. autopep8 for example can automatically re-indent your code and fix other indentation errors as well.
Even the best tools though will sometimes not be able to fix all of your indentation errors and you’ll have to fix them manually. That’s why it’s important to always properly indent your code from the start.
A note about «SyntaxError» related indentation problems
Although not often, sometimes certain SyntaxError exceptions are raised due to incorrect indentation. For example, look at the code below:
if True:
pass
pass # oops! this statement should be indented!.
else:
pass
When the above code is run, a SyntaxError is raised:
Traceback (most recent call last):
File "python", line 4
else:
^
SyntaxError: invalid syntax
Although Python raises a SyntaxError, the real problem with the above code is that the second pass statement should be indented. Because the second pass isn’t indented, Python doesn’t realize that the previous if statement and the else statement are meant to be connected.
The fix for this type of error is to simply correctly re-indent your code. To see how to properly indent your code, see the section How do I indent my code?.
I’m still having a hard time with Python’s indentation syntax. What do I do?
Don’t get discouraged if you’re still struggling. It can take time to get use to
Python’s whitespace syntax rules. Here are some tips to help:
- Get an editor that will tell you when you have an indentation error. Some goods ones are as said above are, PyCharm, SublimeText, and Jupyter Notebook.
- When you indent your code, count out loud to yourself how many times you press the space-bar (or tab key). For example, if you needed to indent a line by four spaces, you would say out loud «one, two, three, four» while simultaneously pressing the space-bar each time. It sounds silly, but it helps train your brain to think about how deep you’re indenting your code.
- If you have an editor, see if it has an option to automatically convert tabs to spaces.
- View others’ code. Browse github or Stackoverflow and see examples of Python code.
- Just write code. That’s the single best way to get better. The more you write Python code, the better you’ll get.
Resources used
- https://en.wikipedia.org/
- https://docs.python.org/3/
- http://python-history.blogspot.com/2009/02/early-language-design-and-development.html
- https://www.python.org/dev/peps/pep-0008/
Время прочтения
8 мин
Просмотры 29K
Recovery mode
Из песочницы
В подавляющем большинстве языков, если во всем исходном тексте программы убрать все отступы, а затем применить автоформатирование, то программа останется полностью рабочей и при этом станет оформлена в едином стиле.
Казалось бы, в случае с Python такая операция не возможна.
По крайней мере, я нигде не смог найти, как моментально обнаружить случайно смещенные отступы в Python. Пришлось решить эту проблему самому.
Вступление
Уважаемый читатель!
Если для тебя близко утверждение:
1) Что программирование — это высокое искусство.
2) Что при программировании на каком-либо языке нужно по возможности максимально использовать всю мощь и разнообразие этого языка для минимализации исходного кода.
3) Что при программировании нужно показать в исходном тексте программы свой высокий уровень, чтобы про твою программу ни кто не мог сказать, что она «тупая».
Если хотя бы один(!) из вышеперечисленных моментов тебе близок, то пожалуйста, не читай эту статью! Не трать, пожалуйста, на нее свое время.
В ней пойдет речь об одном совершенно надуманном и абсурдном моменте программирования.
Уважаемый читатель!
Если для тебя уже близко утверждение:
1) Что программирование — это рутинная, довольно однообразная работа, похожая просто на рытье бесконечной извилистой канавы.
2) Что при программировании на каком-либо языке нужно использовать определенный минимально-оптимальный набор команд языка (возможно отбросив большую часть его команд), чтобы в твоей программе легко(!) разобрался даже программист-юниор.
3) Что при программировании твоя программа должна быть в определенной степени «тупой». Чтобы после того, как ты ее внедрил, ты мог заняться новым проектом и спокойно поставить программиста-юниора, участвовавшего в проекте, на ее сопровождение и доработку под регулярные небольшие новые требования заказчика.
Если все эти три вышеперечисленные утверждения для тебя верны, то, возможно, у тебя присутствует проблема, решение которой я и хочу предложить.
Основные недостатки Python:
1) Python «не минимизирован» по использованию ресурсов и своих данных и, таким образом, не подходит для написания программ, требовательных к использованию ресурсов, таких как мобильные приложения, программы низкого уровня (драйвера, резидентные программы и т.п.) и т.д.
2) Python медленный и однопоточный ( GIL — Global Interpreter Lock ).
3) В Python программные блоки основаны ТОЛЬКО(!) на отступах. Из-за этого:
- уменьшается «читабильность» программ (см.ниже);
- невозможно полноценное автоформатирование исходного текста;
- появляется вероятность возникновения ошибки при случайном и незамеченном смещении отступов, которую иногда бывает очень трудно найти и исправить.
Первый недостаток Python сгладить сложно, и тут он просто имеет ограничение в сфере своего использования. Но это естественный момент, т.к. невозможно придумать язык, который был бы максимально эффективен во всех сферах выполняемых задач.
Второй недостаток Python решается тем, что у него прекрасная двусторонняя интероперабельность с C/C++.
Часто успешный проект развивается довольно стремительно. И сначала высоких требований к быстродействию нет, и в Python при необходимости используют крошечные вставки на С/С++.
Но по мере развития и расширения проекта, требования к быстродействию соответственно возрастают, и Python все чаще начинает выполнять функции вызываемого языка из С/С++. При этом, роль самого Python не уменьшается, т.к. при программировании участков, не требующих высокой скорости выполнения (а их обычно довольно много в крупных проектах), Python является более удобным инструментом, чем С/С++.
А для третьего недостатка Python я хотел бы предложить свой вариант решения.
Все вы знаете, что для подавляющего большинства языков очень часто используется автоформат исходного текста.
Т.е. с какими бы отступами ни была написана программа на этом языке, при запуске автоформатирования все отступы будут приведены к стандартному виду. Для Python такое кажется невозможным.
Любой программист, написавший проекты в несколько тысяч строк языка, знает, что процесс разработки — это не просто придумывание очередного куска программы и его наполнение, а постоянное перемещение участков кода то в подпрограмму, то между блоками программы, то в общие внешние модули и т.п.
Тем более, что на практике юзеры/заказчики уже на начальной стадии, поработав с первыми набросками программы, начинают менять и дополнять задачи конечного проекта, что приводит к сильной корректировке исходного кода.
И тогда в Python, в случае значительного изменения десятков кусков чужой(!) программы (или же своей, но которую уже совершенно не помнишь), стоит при переносе блока случайно зацепить лишний участок кода, принадлежащего другому блоку, то программа может остаться полностью работоспособной, но алгоритм ее работы поменяется (читай «программа начнет работать неправильно»), и найти место такой ошибки в чужой программе и потом правильно восстановить отступы иногда бывает очень непросто!
В этом случае можно, конечно, посмотреть исходный текст (до изменений), но если уже внес в этом месте много корректировок, то придется «отматывать» всю эту цепочку исправлений.
Решение проблемы отступов в Python
Отступы в Python формируются следующими командами:
- class
- def
- for
- while
- if
- try
- with
И для удаления зависимости от отступов, для каждой из этих команд я решил взять за правило использовать «завершающую» команду, которая однозначно будет закрывать блок команд (отступов).
Команды «class» и «def»
Для команд class/def обычно нет проблемы с завершением блока отступов, т.к. блок закрывается новой командой class/def.
Единственный случай — это наличие одной или нескольких подпрограмм, объявленных внутри другой подпрограммы/метода.
def ppg_1():
def ppg_2():
... команды ppg_2 ...
def ppg_3():
... команды ppg_3 ...
... команды ppg_3 ...
... команды ppg_3 ...
... команды ppg_1 ...
Тогда, если случайно сместить блок команд последней внутренней подпрограммы, то он сольётся с командами подпрограммы/метода, в которой объявлена эта внутренняя подпрограмма.
def ppg_1():
def ppg_2():
... команды ppg_2 ...
def ppg_3():
... команды ppg_3 ...
... команды ppg_3 ...
... команды ppg_3 ...
... команды ppg_1 ...
В этом случае в конце этой внутренней подпрограммы/метода нужно просто поставить «return», что и будет четко обозначать окончание блока её команд.
def ppg_1():
def ppg_2():
... команды ppg_2 ...
def ppg_3():
... команды ppg_3 ...
... команды ppg_3 ...
... команды ppg_3 ...
return
... команды ppg_1 ...
Команды «for» и «while»
В конце оператора «for» и «while» нужно ставить «continue».
Т.е. команда будут выглядеть так:
for <...> : # начало блока
... команды ....
continue # конец блока
и
while <...> : # начало блока
... команды ....
continue # конец блока
Например:
... команды ...
for i in range(10):
... команды for ...
... команды for ...
... команды for ...
... команды ...
Случайное удаление отступа в последних командах блока «for» не приводит к ошибке выполнения программы, но приводит к ошибочным результатам! И очень не просто найти такой сбой, если точно не знаешь алгоритм программы (например, если это программа уволившегося коллеги)!
Вот как здесь:
... команды ...
for i in range(10):
... команды for ...
... команды for ...
... команды for ...
... команды ...
А в нижеуказанном примере случайное удаление отступа сразу выдаст ошибку:
... команды ...
for i in range(10):
... команды for ...
... команды for ...
... команды for ...
continue
... команды ...
Команда «if»
В конце оператора «if» нужно ставить команду «elif 0: pass», а вместо «else» использовать команду «elif 1:».
Т.е. для «if» будет законченный блок команд:
if <> # начало блока
... команды ....
elif <>
... команды ....
elif 1: # вместо "else"
... команды ....
elif 0: pass # конец блока
Например:
... команды ...
if result != -1 :
... команды if ...
... команды if ...
... команды if ...
elif 0: pass
... команды ...
Если оформить так, как показано выше, то в блоке команд «if… elif 0: pass» удаление отступа сформирует ошибку запуска.
Без «elif 0: pass», если потом случайно удалятся отступы в последних строках блока «if», то сначала будешь искать место, из-за которого программа неожиданно стала неправильно работать, а потом думать: какие отступы должны быть в блоке, а какие — нет.
... команды ...
if result != -1 :
... команды if ...
... команды if ...
... команды if ...
... команды ...
Почему еще, на мой взгляд, желательно закрывать блоки команд, созданные операторами «for»,
«while», «if» и т.д…
Потому что, когда смотришь на участок кода, где присутствует большая разница в уровне
отступов между непосредственно концом текущего блока и началом следующего, то часто уже не можешь понять, какой отступ чему принадлежит.
Тогда конструкции с «continue» и «elif 0: pass», помимо защиты от случайного удаления, позволят также указать какой блок чем начат и написать комментарий к нему.
Например, видишь конец большого блока:
... команды ...
... команды ...
... команды ...
... команды ...
... команды ...
... команды ...
... команды ...
... команды ...
elif result == 1 :
... команды ...
... команды ...
... команды ...
... команды ...
И сложно вспомнить, что значит каждый уровень отступов.
Но уже гораздо проще, когда это выглядит вот так:
... команды ...
... команды ...
... команды ...
... команды ...
continue # убираем символов b'код\r\n' по словарю
... команды ...
... команды ...
... команды ...
... команды ...
elif 0: pass # варианты "закончили ряд" или "весь товар"
elif 0: pass # Если был спец.коды - обрабатываем
continue # цикл по сканированию кодов
continue # цикл бесконеч., выход - когда "весь товар"
elif result == 1 :
... команды ...
... команды ...
... команды ...
... команды ...
Команда «try»
Тут полная аналогия с «if».
try: # начало блока
... команды ....
except <...>:
... команды ....
except 1: # вместо "else"
... команды ....
except 0: pass # конец блока
Единственная проблема — команда «finally:». После нее больше нельзя поставить ни одну из команд текущего try-блока.
Поэтому если есть необходимость в ее использовании, то для сохранения возможности автоформата и защиты от случайного удаления отступов нужно убрать весь блок команд после «finally:» в локальную подпрограмму (т.е. объявить её как подпрограмму внутри текущей подпрограммы).
Т.е. текст с «finally:» будет таким:
def my_ppg():
...
return
...
finally:
my_ppg()
...
В этом случае тоже можно спокойно применить автоформатирование и не бояться
случайного удаления отступов.
Команда «with»
Для «with» в Python нет никаких дополнительных команд, которые могли бы послужить концом блока. Поэтому ситуация с «with» аналогична ситуации с «finally».
Т.е. либо мы все команды, выполняющиеся в блоке оператора «with», выносим в локальную подпрограмму, либо… А вот дальше я скажу жутко кощунственную вещь: «… либо просто не нужно его никогда использовать.»
Дело в том, что «with», с одной стороны, всего лишь «обертка» для существующих команд Python (т.е. ее всегда можно заменить аналогичным набором команд), с другой стороны, практика показала, что для программистов-юниоров этот контекстный менеджер трудноват для полноценного освоения. И поэтому, если хочешь, чтобы после тебя внедренный проект спокойно сопровождал программист-юниор, то не нужно в проекте использовать команды, затрудняющие его работу.
Заключение
Я думаю вы уже поняли, что если на Python написать программу с применением ВЕЗДЕ(!) вышеуказанных приемов оформления блоков отступов, то достаточно легко написать ПОЛНОЦЕННОЕ АВТОФОРМАТИРОВАНИЕ такой программы даже при «перекосе» или полном удалении отступов в ней, т.к. для всех блоков команд есть начало и конец блока, не зависящие от отступов.
А теперь с улыбкой поставим вопрос так: «Какие недостатки есть у Python, если правильно оформлять блоки отступов, при необходимости взаимодействовать с С/С++ и не применять Python в мобильных и ресурсокритичных приложениях?».
Ответ: «Только несущественные недостатки. Т.е. по большому счету — нет.»
И при такой постановке вопроса нам останется только наслаждаться основными достоинствами Python.
- Простота.
- Минимальный цикл тестирования участков: написал-запустил-проверил.
- Мощность — библиотеки/фреймворки для Python есть «на любой вкус и цвет».
Эти три достоинства вместе дают, на мой взгляд, практически идеальный вариант языка (не забываем, что это только при соблюдении условий, указанных в вопросе выше!).
Отступы в Python строгие. Очень важно соблюдать их в коде.
Если неправильно организовать отступы, пробелы или табуляции в программе, то вернется ошибка IndentationError: expected an intended block.
В этом руководстве рассмотрим, что это за ошибка и когда она появляется. Разберем пример и посмотрим, как решить эту проблему.
Языки программирования, такие как C и JavaScript, не требуют отступов. В них для структуризации кода используются фигурные скобы. В Python этих скобок нет.
Структура программы создается с помощью отступов. Без них интерпретатор не сможет корректно распознавать разные блоки кода. Возьмем такой код в качестве примера:
def find_average(grades):
average = sum(grades) / len(grades)
print(average)
return average
Откуда Python знает, какой код является частью функции find_average(), а какой — основной программы? Вот почему так важны отступы.
Каждый раз, когда вы забываете поставить пробелы или символы табуляции, Python напоминает об этом с помощью ошибки отступа.
Пример возникновения ошибки отступа
Напишем программу, которая извлекает все бублики из списка с едой в меню. Они после этого будут добавлены в отдельный список.
Для начала создадим список всей еды:
lunch_menu = ["Бублик с сыром", "Сэндвич с сыром", "Cэндвич с огурцом", "Бублик с лососем"]
Меню содержит два сэндвича и два бублика. Теперь напишем функцию, которая создает новый список бубликов на основе содержимого списка lunch_menu:
def get_bagels(menu):
bagels = []
for m in menu:
if "Бублик" in m:
bagels.append(m)
return bagels
get_bagels() принимает один аргумент — список меню, по которому она пройдется в поиске нужных элементов. Она проверяет, содержит ли элемент слово «Бублик», и в случае положительного ответа добавит его в новый список.
Наконец, функцию нужно вызвать и вывести результат:
bagels = get_bagels(lunch_menu)
print(bagels)
Этот код вызывает функцию get_bagels() и выводит список бубликов в консоль. Запустим код и посмотрим на результат:
File "test.py", line 4
bagels = []
^
IndentationError: expected an indented block
Ошибка отступа.
Решение ошибки IndentationError
Ошибка отступа сообщает, что отступ был установлен неправильно. Его нужно добавить на 4 строке. Посмотрим на код:
def get_bagels(menu):
bagels = []
Значение переменной bagels должно присваиваться внутри функции, но этого не происходит, что и приводит к ошибке. Для решения проблемы нужно добавить отступ:
def get_bagels(menu):
bagels = []
Теперь запустим код:
['Бублик с сыром', 'Бублик с лососем']
Код нашел все бублики и добавил их в новый список. После этого вывел его в консоль.
Вывод
Ошибка IndentationError: expected an indented block возникает, если забыть добавить отступ в коде. Для исправления нужно проверить все отступы, которые должны присутствовать.
Введение
Примеры
IndentationErrors (или отступ SyntaxErrors)
В большинстве других языков отступ не является обязательным, но в Python (и других языках: ранних версиях FORTRAN, Makefiles, Whitespace (эзотерический язык) и т. Д.) Это не так, что может сбивать с толку, если вы пришли с другого языка если вы копировали код из примера в свой собственный, или просто если вы новичок.
IndentationError / SyntaxError: неожиданный отступ
Это исключение возникает, когда уровень отступа увеличивается без причины.
пример
Там нет причин для повышения уровня здесь:
print «Эта строка в порядке» print «Эта строка не в порядке» print(«Эта строка не в порядке») print(«Эта строка не в порядке»)
Здесь есть две ошибки: последняя и что отступ не соответствует ни одному уровню отступа. Однако показано только одно:
print «Эта строка в порядке» print «Эта строка не в порядке» print(«Эта строка не в порядке») print(«Эта строка не в порядке»)
IndentationError / SyntaxError: unindent не соответствует ни одному внешнему уровню отступа
Похоже, вы не удалили полностью.
пример
def foo (): print «Это должно быть частью foo ()» print «ERROR!» print «Это не часть foo ()» print(«Эта строка не в порядке») print(«Эта строка не в порядке»)
IndentationError: ожидается блок с отступом
После двоеточия (а затем и новой строки) уровень отступа должен увеличиться. Эта ошибка возникает, когда этого не произошло.
пример
if ok:
doStuff()
Примечание: Используйте ключевое слово pass (что не делает абсолютно ничего) просто Погружает if , else , за except , class , method или definition , но не сказать , что произойдет , если называется / условие истинно (но сделать это позже, или в случае за except : просто ничего не делать):
def foo():
pass
IndentationError: противоречивое использование табуляции и пробелов в отступе
пример
def foo():
if ok:
return "Two != Four != Tab"
return "i dont care i do whatever i want"
Как избежать этой ошибки
Не используйте вкладки. Это обескураживает PEP8 , в стиль руководства для Python.
- Установите редактор использовать 4 пробелов для отступа.
- Сделайте поиск и замените, чтобы заменить все вкладки с 4 пробелами.
- Убедитесь , что ваш редактор настроен на отображение вкладок в 8 пробелов, так что вы можете легко реализовать эту ошибку и исправить ее.
Смотрите этот вопрос , если вы хотите , чтобы узнать больше.
TypeErrors
Эти исключения возникают, когда тип какого-либо объекта должен быть другим
Ошибка типа: [определение / метод] занимает? позиционные аргументы, но? был дан
Функция или метод вызывались с большим (или меньшим) количеством аргументов, чем те, которые он может принять.
пример
Если дано больше аргументов:
def foo(a): return a
foo(a,b,c,d) #And a,b,c,d are defined
Если дано меньше аргументов:
def foo(a,b,c,d): return a += b + c + d
foo(a) #And a is defined
Примечание: если вы хотите использовать неизвестное количество аргументов, вы можете использовать *args или **kwargs.См * арг и ** kwargs
Ошибка типа: неподдерживаемые типы операндов для [операнд]: ‘???’ а также ‘???’
Некоторые типы не могут работать вместе, в зависимости от операнда.
пример
Например: + используется для конкатенации и добавить, но вы не можете использовать любой из них для обоих типов. Например, пытаясь сделать set путем конкатенации ( + ю) 'set1' и 'tuple1' дает ошибку. Код:
set1, tuple1 = {1,2}, (3,4)
a = set1 + tuple1
Некоторые виды (например: int и string ) используют как + , но и для различных вещей:
b = 400 + 'foo'
Или они могут даже не использоваться ни для чего:
c = ["a","b"] - [1,2]
Но вы можете, например , добавить float к int :
d = 1 + 1.0
Ошибка типа: ‘???’ объект не повторяем / подписан:
Для объекта быть итерацией он может принимать последовательные индексы , начиная с нуля , пока индексы больше не действительны и IndexError поднято (Технически: он должен иметь __iter__ метод , который возвращает __iterator__ , или который определяет __getitem__ метод , который делает что было упомянуто ранее).
пример
Здесь мы говорим , что bar является нулевым пунктом 1. Глупости:
foo = 1
bar = foo[0]
Это более дискретный вариант: В этом примере for пытается установить x , чтобы amount[0] , первый элемент в качестве итератора , но он не может , поскольку количество представляет собой INT:
amount = 10
for x in amount: print(x)
Ошибка типа: ‘???’ объект не вызывается
Вы определяете переменную и вызываете ее позже (например, что вы делаете с функцией или методом)
пример
foo = "notAFunction"
foo()
NameError: name ‘???’ не определено
Возникает, когда вы пытались использовать переменную, метод или функцию, которые не инициализированы (по крайней мере, до этого). Другими словами, оно возникает, когда запрошенное локальное или глобальное имя не найдено. Вполне возможно , что вы орфографические ошибки имени объекта или забыли import что — то. Также возможно это в другом объеме. Мы рассмотрим их на отдельных примерах.
Это просто не определено нигде в коде
Возможно, вы забыли инициализировать его, особенно если это константа
foo # This variable is not defined
bar() # This function is not defined
Может быть, это будет определено позже:
baz()
def baz():
pass
Или это не import изд:
#needs import math
def sqrt():
x = float(input("Value: "))
return math.sqrt(x)
Области применения Python и правило LEGB:
В так называемом правиле LEGB говорится о возможностях Python. Его название основано на различных областях, упорядоченных по соответствующим приоритетам:
Local → Enclosed → Global → Built-in.
- L OCAL: Переменные не объявляются глобальные или назначены в функции.
- Е nclosing: Переменные , определенные в функции , которая намотана внутри другой функции.
- G ЛОБАЛЬНЫЕ: Переменные , объявленные глобальные или назначены на верхнем уровне файла.
- B uilt в: Переменные в наперед заданные имена встроенных модуля.
В качестве примера:
for i in range(4):
d = i * 2
print(d)
d является доступным , поскольку for цикла не ознаменует новую сферу, но если это так, то мы имели бы ошибку и его поведение будет выглядеть следующим образом:
def noaccess():
for i in range(4):
d = i * 2
noaccess()
print(d)
Python говорит NameError: name 'd' is not defined
Другие ошибки
AssertError
assert утверждение существует практически в каждом языке программирования. Когда вы делаете:
assert condition
или же:
assert condition, message
Это эквивалентно этому:
if __debug__:
if not condition: raise AssertionError(message)
Утверждения могут включать необязательные сообщения, и вы можете отключить их, когда закончите отладку.
Примечание: встроенная переменная отладки Правда при нормальных условиях, Ложные при оптимизации запрашиваемых (опция командной строки -O). Задания для отладки являются незаконными. Значение для встроенной переменной определяется при запуске интерпретатора.
KeyboardInterrupt
Ошибка возникает , когда пользователь нажимает клавишу прерывания обычно Ctrl + C или дель.
ZeroDivisionError
Вы пытались вычислить 1/0 , который не определен. Посмотрите этот пример, чтобы найти делители числа:
div = float (raw_input («Divisors of:»)) для x в xrange (div + 1): # включает само число и ноль, если div / x == div // x: print x, «является делителем» Div div = int (input («Divisors of:»)) для x в диапазоне (div + 1): # включает само число и ноль, если div / x == div // x: print(x, «является делителем», див) Он вызывает `ZeroDivisionError`, потому что цикл` for` присваивает это значение `x`. Вместо этого должно быть: div = float (raw_input («Divisors of:»)) для x в xrange (1, div + 1): # включает в себя само число, но не ноль, если div / x == div // x: print x, «является делитель», див div = int (input («Divisors of:»)) для x в диапазоне (1, div + 1): # включает само число, но не ноль, если div / x == div // x: print(x, «is делитель», div)
Синтаксическая ошибка в хорошем коде
В большинстве случаев ошибка SyntaxError, указывающая на неинтересную строку, означает, что в строке перед ней есть проблема (в данном примере это пропущенная скобка):
def my_print():
x = (1 + 1
print(x)
Возвращает
File "<input>", line 3
print(x)
^
SyntaxError: invalid syntax
Как показано в примере, наиболее распространенной причиной этой проблемы являются несоответствующие скобки / скобки.
В Python 3 есть одно важное предупреждение для операторов печати:
>>> распечатать «Привет мир» Файл » «, строка 1 print» hello world «^ SyntaxError: неверный синтаксис, поскольку [оператор` print` был заменен функцией `print()`] (https://docs.python.org/3/whatsnew/3.0.html # print-is-a-function), так что вы хотите: print(«hello world») # Обратите внимание, что это справедливо как для Py2, так и для Py3
Синтаксис
Параметры
Примечания
На чтение 3 мин. Просмотров 389 Опубликовано 18.04.2021
Python – это развивающийся язык программирования, который был впервые выпущен в 1991 году. Этот язык известен своей большой всеобъемлющей библиотекой и поддерживает несколько парадигм программирования, таких как функциональное, императивное, процедурное и объектно-ориентированное.
‘ Ошибка отступа: ожидается блок с отступом ‘ встречается у всех типов пользователей ; будь то новички или опытные. Поскольку Python упорядочивает весь свой код с помощью правильных пробелов, если у вас плохой отступ, код не будет компилироваться, и вам будет возвращено сообщение об ошибке.
Согласно соглашениям, принятым в PEP8, при необходимости должно быть четыре пробела. Для каждого программиста идеально использовать правильные отступы, чтобы улучшить читаемость кода.
Содержание
- Что вызывает ошибку отступов в Python?
- Решение 1. Проверка неправильных пробелов/табуляций
- Решение 2: Включение символов табуляции/пробела в редакторе
Что вызывает ошибку отступов в Python?
Like Как упоминалось ранее, эта ошибка в основном возникает из-за того, что в вашем коде есть пробелы или табуляции. Поскольку Python использует процедурный язык, вы можете столкнуться с этой ошибкой, если вы неправильно разместили табуляции/пробелы. Программа может работать правильно, но если интерпретатор обнаружит эту ошибку, сообщение об ошибке появится посередине. Некоторые из причин ошибки:
- В вашем коде используются как пробелы, так и табуляции . Если оба используются взаимозаменяемо, интерпретатор не сможет определить, какой элемент использовать.
- Вы разместили отступ неправильно . Если практика отступов не соблюдается, эта ошибка неизбежно возникнет.
- Вы забыли сделать отступ для составных операторов , таких как ‘if’, ‘for’, ‘while’ и т. д.
- Вы забыли сделать отступ для пользовательских функций или классов .
Решение 1. Проверка неправильных пробелов/табуляций
Для этой проблемы нет мгновенного решения. Поскольку код ваш, вы должны просмотреть каждую строку и посмотреть, где вы допустили ошибку. В коде есть несколько блоков по структуре. Если есть оператор ‘If’, в коде, который следует за ним, должен быть отступ.
Посмотрите на диаграмму выше. Убедитесь, что отступ для определенного блока остается неизменным во всем коде, даже если новый блок вводится посередине. Убедитесь, что ваш отступ согласован. Если вы используете пробелы, всегда используйте пробелы, а если вы используете табуляции, всегда используйте табуляции. Смешивание двух элементов вызовет проблемы.
Правильный отступ показан в приведенном выше примере. См. Цикл «for» для начала. Все внутри цикла for должно иметь отступ. Внутри цикла for у нас есть оператор if. Внутри оператора «if» все должно иметь больше отступов..
Вы можете легко проверить, где произошла ошибка отступа, проверив журнал ошибок и посмотрев строку, откуда возникла ошибка.
Решение 2: Включение символов табуляции/пробела в редакторе
Если вам трудно сделать отступ в коде «догадываться», как это делают все программисты, вы можете включить символы табуляции/пробела в ваша IDE или редактор кода. Эта опция активирует маленькие «точки» в вашем коде, где каждая точка представляет собой пробел или табуляцию. Вы можете использовать это для более правильного отступа кода и убедиться, что нет лишнего отступа или некоторые из них отсутствуют.
В этом примере мы возьмем Notepad ++ и посмотрим, как вы можете включить символы. Если вы используете другое программное обеспечение для редактирования кода, вы можете включить настройку, относящуюся к нему.
- Нажмите Вид> Показать символ> Показать пробелы и TAB
- Теперь опция включена. Вы также можете включить Руководство по отступам , чтобы вам было проще.
Посмотрите пример выше. См. Отступ, реализованный после каждого класса. Каждое пространство представлено одной точкой. После внесения изменений в неправильный отступ в коде запустите его еще раз и посмотрите, решит ли это проблему.
Содержание:развернуть
- Почему табуляция в Питоне так важна?
- Что нам говорит PEP8?
- Примеры кода
-
👍 Правильное оформление
-
👎 Ошибочное оформление
-
😐 Выборочное оформление
- Табуляция или пробелы — что использовать? 🤷♂️
- Настройка IDE для работы с отступами
-
PyCharm
-
VSCode
- Ошибки при работе с отступами
Одна из особенностей Python — для оформления блоков кода вместо привычных фигурных скобок, как в C, C ++, Java или операторных скобок begin … end как в Pascal, используются отступы (или табуляция).
Подробнее о том, какие есть правила расстановки отступов — рассмотрим далее.
Почему табуляция в Питоне так важна?
Что такое отступ? Говоря простыми словами, это просто добавление пробела перед определенным оператором.
Отступы — важная концепция языка Питон, так как без правильного их оформления в итоге программист получит ошибку типа IndentationError, код при этом не будет скомпилирован.
Многим программистам жесткое соблюдение отступов может показаться избыточной мерой. Однако именно из-за строго соблюдения правил форматирования, код на Python — чистый, понятный и аккуратный. Отсюда следующие плюсы 👍:
- Не нужно проверять, не потерялась ли лишняя скобка;
- Читать такой код удобнее (по «Философии Python» — читаемость имеет значение);
- Легче работать со сторонними библиотеками;
- Код вашего коллеги будет максимально похож на ваш код.
💁♂️ Чтобы понять, насколько это важно, можно представить ситуацию, когда в книге удалить все номера страниц, в результате чего нельзя будет понять, где продолжать чтение. Без использования indent-отступа интерпретатор Python не сможет определить, какой оператор необходимо выполнять следующим, что относится к разным блокам кода. В результате и возникает исключение типа IndentationError.
Отступы в языке Python — это способ указать интерпретатору, что оператор (или целая их группа) — это определенный block-комбинация команд для выполнения задачи.
В большинстве других языков, таких как семейство C, Java и прочих для оформления блоков используются фигурные скобки, в Питоне — отступы, для создания которых обычно используются пробелы. Все команды, отделенные от начала строки одним и тем же расстоянием, принадлежат к одному и тому же блоку. Если в нем выделяется еще один блок — используется еще один отступ вправо, и так далее. Рассмотрим это на примере:
def my_small_function(): # [0 пробелов] определение функции со знаком «:» в конце
if a > b: # [4 пробела] начало блока условия, располагается внутри функции
return a # [8 пробелов] часть блока if
else: # [4 пробела] продолжение блока условия, на том же уровне, что и if
return b # [8 пробелов] часть блока else
print(my_small_function()) # [0 пробелов] вызов функции вне ее блока
💡 По умолчанию в Python используется 4 пробела в качестве отступа
Однако программист может использовать и другое их количество, но не менее одного.
Что нам говорит PEP8?
Для каждого уровня отступов необходимо использовать по 4 пробела.
Строки большой длины должны вертикально выравнивать внутренние элементы, для этого используется неявная линия в скобках или с применением висячего отступа. Во втором случае следует помнить: на первой линии не должны располагаться аргументы, остальные строки располагаются так, чтобы быть продолжением неявной линии.
Примеры кода
👍 Правильное оформление
# Выравнивание выполнено по открывающей скобке
foo = name_of_function(one, two,
three, four)
# Дополнительные отступы используются для выделения блока от остальных
def name_of_function(
one, two, three,
four):
print(one)
Расположение закрывающих скобок в конструкциях с многими строками под началом первой строки:
my_list = [
one, two, three,
four, five, six,
]
result = some_arguments(
'1', '2', '3',
'4', '5', '6',
)
👎 Ошибочное оформление
# Без вертикального выравнивания аргументы не должны располагаться на первой линии
foo = name_of_function(one, two,
three, four)
# Используется больше отступов для выделения блока от остальных
def name_of_function(
one, two, three,
four):
print(one)
😐 Выборочное оформление
# Использование небольших отступов
foo = name_of_function(
one, two,
three, four)
В многострочных конструкциях закрывающие скобки можно устанавливать на отдельной строке под первым символом (не пробелом) последнего пункта:
some_list = [
one, two, three,
four, five, six,
]
res = some_arguments(
'1', '2', '3',
'4', '5', '6',
)
Табуляция или пробелы — что использовать? 🤷♂️
Согласно официальной документации, самым предпочтительным способом оформления отступов является использование пробелов, обычно 4
Табуляция может использоваться в случае поддержки готового кода, где все отступы оформлены именно таким способом.
В Python 3 версии запрещено оформлять отступы с использованием табуляции и пробелов, только какой-то один способ. Во второй версии интерпретатор пытается преобразовывать табуляцию в пробелы. Так, при вызове интерпретатора в командной строке с использованием параметра -t появляется предупреждение о наличии смешанного стиля оформления отступов. Если же запуск выполнен с параметром -tt, в этих местах кода будут ошибки. Так что рекомендуется использовать вызова интерпретатора именно с этими параметрами.
Настройка IDE для работы с отступами
Чтобы при написании кода не задумываться о правильной расстановке пробелов для отступов, в редакторах кода и IDE используется специальный функционал, самостоятельно распознающий место создания отдельных блоков, в результате чего пробелы расставляются автоматически.
Рассмотрим, как можно настроить или изменить такие параметры в самых популярных IDE, когда возникает такая необходимость.
PyCharm
В случае использования интегрированной среды разработки PyCharm для настройки оформления отступов необходимо последовательно перейти по таким пунктам меню:
File → Settings → Editor → Code style → Python
Для настроек параметров есть 3 поля:
- Tab size — количество пробелов при нажатии клавиши Tab;
- Indent — количество пробелов для одного отступа;
- Continuation indent — количество пробелов для отступа, когда следующая строка продолжает предыдущую.
💭 Еще одна полезная опция — отображение точек вместо каждого пробела, что особо удобно при поддержке чужого кода. В PyCharm для активации этой функции следует перейти File → Settings → Editor → General → Appearance → Show whitespaces, установив галочку напротив соответствующего пункта.
VSCode
Для настройки аналогичных функций в VSCode нужно нажать комбинацию клавиш ctrl + , или перейти по пунктам меню
File → Preferences → Settings
Далее для ускорения в строке поиска ввести tab и установить нужные значения для таких опций:
- editor: insert spaces — использовать ли пробелы вместо табуляции;
- editor: tab size — желаемое количество пробелов для одного отступа.
Ошибки при работе с отступами
При неправильном оформлении отступов интерпретатор Python будет сообщать об ошибках. Таких ошибок может быть несколько, рассмотрим основные.
expected an indented block
Данная ошибка может возникать в случае, когда после оглашения начала блока кода — def, if, while и некоторых других на следующей строке отсутствует отступ. Для ее исправления после начала блока должна быть хотя бы одна вложенная строка с отступом.
unexpected indent
Возникает ошибка в том случае, когда перед началом строки есть отступ, но на предыдущей отсутствует оглашение начала блока кода, то есть, нет def, if, elif, else, for или while. Обычно такая ситуация возникает случайно, когда программист ставит слишком много пробелов в начале строки.
Indentationerror: expected an indented block
Ошибка возникает в том случае, когда после оглашения блока кода на следующей строке нет отступа или же сделанные отступы состоят из разного количества пробелов.
Таким образом, отступы в языке программирования Python, в отличие от многих других, играют такую же важную роль, как и служебные слова, так как именно они определяют создание блоков кода. Для каждого indent рекомендуется использовать 4 пробела, однако программист по своему желанию может установить и другое их количество, главное — одинаковое во всем проекте.
Python – один из самых популярных языков программирования в мире. Поскольку это интерпретируемый язык, он дает разработчикам большую гибкость при написании кода. Но с большой свободой приходит и большая ответственность и еще больше возможностей для совершения ошибок. В этой статье мы разберем ошибки программистов Python, которые встречаются чаще всего. Также мы расскажем, как их исправить.
Мы рассмотрим следующие ошибки:
- Неправильные отступы
- ImportError
- Изменяемые аргументы, установленные по умолчанию
- Забытое двоеточие
- Несоответствие скобок
- Неправильное применение функции инициализации
- Изменение значений переменных класса без использования имени класса
- Непонимание правил области видимости в Python
- Непонимание того, как Python связывает переменные в замыканиях
- Исчерпание итераторов
Неправильные отступы
В Python отступ указывает, относится ли данная строка к предыдущему оператору в блоке кода. Официальные правила стиля Python (PEP 
Чтобы исправить ошибку отступа, попробуйте сделать следующее:
- Используйте пробелы или табы, но не комбинируйте их. Будьте особенно внимательны, так как вы можете не осознавать, что использовали и табы, и пробелы, если полученный отступ выглядит одинаково. Преобразование табов в пробелы (или наоборот) скорее всего можно настроить в вашем редакторе кода или IDE.
- Следите за количеством пробелов, которые вы используете. Следовать рекомендации PEP 8 о четырех пробелах не обязательно, но какое бы число вы ни выбрали, придерживайтесь его! К примеру, если вы делаете отступы по 2 пробела, то везде должно быть 2 пробела.
ImportError
Возможно, вы импортируете встроенный модуль, который, как вы уверены, находится в стандартной библиотеке Python, но, к вашему удивлению и разочарованию, интерпретатор возвращает ImportError.
Эта проблема обычно возникает, когда разработчики импортируют в свою библиотеку файл, имя которого совпадает с именем одного из встроенных модулей стандартной библиотеки. В таких ситуациях Python отдает приоритет установленному вами модулю с таким же именем, а не встроенному модулю стандартной библиотеки.
Решение? Просто переименуйте файл в своей библиотеке и дайте ему уникальное имя, которое не используется в модулях стандартной библиотеки.
[python_ad_block]
Использование изменяемых типов для аргументов, устанавливаемых по умолчанию
Другая распространенная проблема возникает при назначении изменяемых типов данных для аргументов по умолчанию. Python оценивает значения по умолчанию для изменяемых типов данных только один раз, во время создания функции. Он не будет инициализировать значение по умолчанию для любого последующего вызова. Вы можете не заметить ничего необычного, если выполняете только один вызов функции в своем коде, однако, если вы вызовете её второй раз, Python будет использовать значение по умолчанию, вычисленное во время первого вызова.
Допустим, вы используете в качестве аргумента по умолчанию изменяемый тип данных, например список. Интерпретатор будет использовать тот же список, который был создан при первоначальном определении функции. Следующий код демонстрирует непонятное поведение, которое может возникнуть при добавлении элементов в такой список:
def some_func(default_arg=[]):
default_arg.append("some_string")
return default_arg
print(some_func())
print(some_func())
print(some_func([]))
print(some_func())
=>['some_string']
=>['some_string', 'some_string']
=>['some_string']
=>['some_string', 'some_string', 'some_string']
Один из способов устранения этой ошибки программирования – присвоить значение по умолчанию None. В следующем коде любое значение, переданное в функцию, соответствует аргументу:
def some_func(default_arg=None):
if default_arg is None:
default_arg = []
default_arg.append("some_string")
return default_arg
print(some_func())
print(some_func())
print(some_func([]))
print(some_func())
=>['some_string']
=>['some_string']
=>['some_string']
=>['some_string']
Забытое двоеточие
Если вы получаете синтаксические ошибки, возможно, вы забыли двоеточие в конце предложения. В коде Python каждое структурное предложение заканчивается двоеточием. Это также относится к заголовкам функций, где двоеточие вызывает отступ для последующих строк внутри функции. Это распространенная ошибка для начинающих разработчиков Python. Чтобы исправить это, просто отрабатывайте это правило до тех пор, пока оно не станет второй натурой: каждое структурное предложение заканчивается двоеточием!
Несоответствие скобок
Это удивительно частая ошибка начинающих разработчиков Python. Как и в математике, количество открытых и закрытых скобок должно совпадать. Обязательно просмотрите свой код и убедитесь, что каждая открытая скобка имеет соответствующую закрытую, чтобы код работал корректно.
Неправильное применение функции инициализации
Используемая как конструктор, функция __init__ создает объект или выделяет память для нового объекта класса. Функция __init__ используется в качестве конструктора, когда объект создается из класса, и позволяет классу инициализировать атрибуты класса. Другими словами, она используется исключительно для установки значений. Однако распространенной ошибкой разработчиков Python является попытка использовать этот метод для возврата значений. Чтобы исправить это, просто запомните, что функция __init__ в Python предназначена исключительно для использования в качестве конструктора класса.
Изменение значений переменных класса без использования имени класса
Поскольку Python — объектно-ориентированный язык, переменные класса и экземпляра работают по-разному.
В отличие от переменных экземпляра, переменные класса используются экземплярами во всем классе. Если вы изменяете переменную класса без использования имени класса, создается переменная экземпляра с тем же именем, что и переменная класса. Новые переменные экземпляра с теми же именами, что и переменные класса, фактически затеняют переменную класса, поэтому, если вы пытаетесь изменить переменную класса во второй раз, объекты в коде вместо этого будут ссылаться на переменные экземпляра.
Чтобы исправить эту ошибку, обязательно используйте имя класса при изменении переменной класса, чтобы все объекты также получили новое значение.
Если ваш код возвращает UnboundLocalError, возможно, вы не разобрались в областях видимости Python. Это распространенная ошибка, с которой сталкиваются разработчики Python при использовании списков.
Уникальный анализ области действия Python основан на правиле LEGB (Local, Enclosing, Global, Built-in). Следуя порядку LEGB, Python сначала предположит, что любая переменная, объявленная в диапазоне, является локальной для этой области, и переопределит любую переменную с тем же именем во внешней области. Это означает, что код, который выполнялся должным образом при объявлении переменной, может позже вернуть UnboundLocalError при повторном вызове функции.
В следующем примере мы рассмотрим код, который изначально работает должным образом:
x = 10
def bar():
print(x)
bar()
=>10
Однако этот код возвращает UnboundLocalError, как только мы попробуем изменить значение переменной х. Согласно порядку LEGB, Python распознает эту операцию для x как для локальной переменной, а не как переменную внешней области видимости.
x = 10
def foo():
print(x)
x += 1
foo()
=>Traceback (most recent call last):
=> File "main.py", line 5, in <module>
=> foo()
=> File "main.py", line 3, in foo
=> print(x)
=>UnboundLocalError: local variable 'x' referenced before assignment
Чтобы исправить UnboundLocalError, просто нужно добавить оператор присваивания, чтобы явно объявить, что переменная является глобальной.
x = 10
def foobar():
global x
print(x)
x += 1
foobar()
=>10
Непонимание того, как Python связывает переменные в замыканиях
Python поздно связывает свои переменные в замыканиях. Это означает, что он вызывает значения переменных, которые были возвращены при первом вызове затронутой функции. Это не всегда может быть проблемой. Но если это все же проблема, вы можете ее исправить, создав замыкание, которое будет немедленно связываться с его аргументами, например с аргументом по умолчанию.
Исчерпанные итераторы
Начинающим разработчикам Python важно понимать, что итераторы и генераторы могут быть исчерпаны. Особенно часто с этой проблемой сталкиваются разработчики, переходящие с Python 2 на Python 3. В Python 3 намного больше генераторов, что помогает сделать его более эффективным. Однако это может быть сложно для тех, кто сталкивается с новыми особенностями, которых не было в Python 2.
Данный тип ошибки может выглядеть следующим образом. В Python 2 вы можете вызвать функцию-итератор, такую как zip(), для объединения двух списков и попытаться затем распечатать этот список. Если вы используете тот же самый код в Python 3, он не вернет вам все значения сразу. Это потому, что вы исчерпали итератор, и у него нет оставшихся значений для возврата.
Вы можете исправить это, просто преобразовав функцию в список с самого начала. Вы можете исчерпать итератор, но не список.
Заключение
Сегодня мы рассмотрели 10 распространенных ошибок программистов Python и пути их устранения. Надеемся статья была вам полезна. Успехов в написании кода!
Перевод статьи «10 common mistakes Python programmers make (and how to fix them)».





