Ошибки программистов Python

Python – один из самых популярных языков программирования в мире. Поскольку это интерпретируемый язык, он дает разработчикам большую гибкость при написании кода. Но с большой свободой приходит и большая ответственность и еще больше возможностей для совершения ошибок. В этой статье мы разберем ошибки программистов Python, которые встречаются чаще всего. Также мы расскажем, как их исправить.

Мы рассмотрим следующие ошибки:

  • Неправильные отступы
  • ImportError
  • Изменяемые аргументы, установленные по умолчанию
  • Забытое двоеточие
  • Несоответствие скобок
  • Неправильное применение функции инициализации
  • Изменение значений переменных класса без использования имени класса
  • Непонимание правил области видимости в Python
  • Непонимание того, как Python связывает переменные в замыканиях
  • Исчерпание итераторов

Неправильные отступы

В Python отступ указывает, относится ли данная строка к предыдущему оператору в блоке кода. Официальные правила стиля Python (PEP 8) рекомендуют использовать отступ в четыре пробела. Однако вы можете выбирать любое количество пробелов, а также пользоваться табами. Какой бы отступ вы ни предпочли, Python требует одного – согласованности.

Чтобы исправить ошибку отступа, попробуйте сделать следующее:

  • Используйте пробелы или табы, но не комбинируйте их. Будьте особенно внимательны, так как вы можете не осознавать, что использовали и табы, и пробелы, если полученный отступ выглядит одинаково. Преобразование табов в пробелы (или наоборот) скорее всего можно настроить в вашем редакторе кода или IDE.
  • Следите за количеством пробелов, которые вы используете. Следовать рекомендации PEP 8 о четырех пробелах не обязательно, но какое бы число вы ни выбрали, придерживайтесь его! К примеру, если вы делаете отступы по 2 пробела, то везде должно быть 2 пробела.

ImportError

Возможно, вы импортируете встроенный модуль, который, как вы уверены, находится в стандартной библиотеке Python, но, к вашему удивлению и разочарованию, интерпретатор возвращает ImportError.

Эта проблема обычно возникает, когда разработчики импортируют в свою библиотеку файл, имя которого совпадает с именем одного из встроенных модулей стандартной библиотеки. В таких ситуациях Python отдает приоритет установленному вами модулю с таким же именем, а не встроенному модулю стандартной библиотеки.

Решение? Просто переименуйте файл в своей библиотеке и дайте ему уникальное имя, которое не используется в модулях стандартной библиотеки.

python logo

Лаборатория Django-разработки

За 3 месяца отработай навыки Django-разработки до профессионального уровня на серьезном проекте под руководством наставника.

×

Использование изменяемых типов для аргументов, устанавливаемых по умолчанию

Другая распространенная проблема возникает при назначении изменяемых типов данных для аргументов по умолчанию. 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 — объектно-ориентированный язык, переменные класса и экземпляра работают по-разному.

В отличие от переменных экземпляра, переменные класса используются экземплярами во всем классе. Если вы изменяете переменную класса без использования имени класса, создается переменная экземпляра с тем же именем, что и переменная класса. Новые переменные экземпляра с теми же именами, что и переменные класса, фактически затеняют переменную класса, поэтому, если вы пытаетесь изменить переменную класса во второй раз, объекты в коде вместо этого будут ссылаться на переменные экземпляра.

Чтобы исправить эту ошибку, обязательно используйте имя класса при изменении переменной класса, чтобы все объекты также получили новое значение.

Непонимание правил области видимости в 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)».