Глючный код Python: 5 самых распространенных ошибок, которые совершают разработчики Python

Глючный код Python: 5 самых распространенных ошибок, которые совершают разработчики Python

Python и 1000 программ


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


О Python

Python — интерпретируемый, объектно-ориентированный высокоуровневый язык программирования с динамической семантикой. Его высокоуровневые встроенные структуры данных в сочетании с динамической типизацией и динамической привязкой делают его очень привлекательным для быстрой разработки приложений, а также для использования в качестве языка сценариев или клея для подключения существующих компонентов или служб. Python поддерживает модули и пакеты, тем самым способствуя модульности программы и повторному использованию кода.


Об этой статье

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


Имея это в виду, в этой статье представлен список «топ-10» несколько тонких, трудно уловимых ошибок, которые могут укусить даже некоторых более продвинутых разработчиков Python сзади.



Распространенная ошибка No 1: Неправильное использование выражений по умолчанию для аргументов функции

Python позволяет указать, что аргумент функции является необязательным, предоставляя для него значение по умолчанию. Хотя это отличная особенность языка, она может привести к некоторой путанице, когда значение по умолчанию изменяется. Например, рассмотрим следующее определение функции Python:



Распространенной ошибкой является мысль о том, что необязательный аргумент будет задан в указанное выражение по умолчанию каждый раз при вызове функции без указания значения для необязательного аргумента. В приведенном выше коде, например, можно было бы ожидать, что многократный вызов (т.е. без указания аргумента) всегда будет возвращать , поскольку предполагается, что каждый раз вызывается (без указания аргумента) установлено значение (т.е. новый пустой список).foo()bar'baz'foo()barbar[]


Но давайте посмотрим, что на самом деле происходит, когда вы это делаете:



Да? Почему он продолжал добавлять значение по умолчанию к существующему списку при каждом вызове, а не создавать новый список каждый раз?"baz"foo()


Более продвинутый ответ программирования python заключается в том, что значение по умолчанию для аргумента функции вычисляется только один раз, во время определения функции. Таким образом, аргумент инициализируется по умолчанию (т.е. пустой список) только тогда, когда он сначала определен, но затем вызовы (т.е. без указания аргумента) будут продолжать использовать тот же список, к которому был первоначально инициализирован.barfoo()foo()barbar


FYI, общий обходной путь для этого заключается в следующем:



Распространенная ошибка No 2: Неправильное использование переменных класса


Рассмотрим следующий пример:



Имеет смысл.



Да, опять же, как и ожидалось.



В Python переменные класса внутренне обрабатываются как словари и следуют тому, что часто называют порядком разрешения методов (MRO). Таким образом, в приведенном выше коде, поскольку атрибут не найден в классе, он будет искаться в его базовых классах (только в приведенном выше примере, хотя Python поддерживает несколько наследований). Другими словами, не имеет собственного свойства, независимого от . Таким образом, ссылки на . Это вызывает проблему Python, если она не обрабатывается должным образом.


Распространенная ошибка No 3: Неправильное указание параметров для блока исключений


Предположим, у вас есть следующий код:



Проблема здесь в том, что оператор не принимает список исключений, указанных таким образом. Скорее, в Python 2.x синтаксис используется для привязки исключения к необязательному второму указанному параметру (в данном случае ), чтобы сделать его доступным для дальнейшей проверки. В результате в приведенном выше коде исключение не перехватывается оператором; скорее, исключение в конечном итоге привязывается к параметру с именем .except except Exception, e e IndexError except IndexError


Правильный способ перехвата нескольких исключений в операторе — указать первый параметр в виде кортежа, содержащего все перехватываемые исключения. Кроме того, для максимальной переносимости используйте ключевое слово, так как этот синтаксис поддерживается как Python 2, так и Python 3:except as



Распространенная ошибка No 4: Неправильное понимание правил области Python

Разрешение области Python основано на так называемом правиле LEGB, которое является сокращением для Local, Enclosing, Global, Built-in. Кажется достаточно простым, не так ли? Ну, на самом деле, есть некоторые тонкости в том, как это работает в Python, что подводит нас к общей более продвинутой проблеме программирования на Python ниже. Обратите внимание на следующее:



В чём проблема?


Приведенная выше ошибка возникает из-за того, что при назначении переменной в области эта переменная автоматически рассматривается Python как локальная для этой области и затеняет любую переменную с аналогичным именем в любой внешней области.


Многие, таким образом, удивляются, получая ранее работающий код, когда он изменяется путем добавления оператора присваивания где-то в теле функции. (Подробнее об этом можно прочитать здесь.)UnboundLocalError


Это особенно часто сбивает разработчиков с толку при использовании списков. Рассмотрим следующий пример:



Да? Почему бомба при этом работала нормально?foo2foo1


Ответ такой же, как и в предыдущем примере, но, по общему признанию, более тонкий. не делает задания , тогда как является. Помня, что на самом деле это просто сокращение для , мы видим, что мы пытаемся присвоить значение (поэтому Python предполагает, что оно находится в локальной области). Тем не менее, значение, которое мы хотим присвоить, основано на самом себе (опять же, теперь предполагается, что оно находится в локальной области), которое еще не определено. Бум.foo1 lst foo2 lst += [5] lst = lst + [5] lst lst lst


Распространенная ошибка No 5: Изменение списка при итерации по нему

Проблема со следующим кодом должна быть довольно очевидной:



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


К счастью, Python включает в себя ряд элегантных парадигм программирования, которые при правильном использовании могут привести к значительному упрощению и упорядочению кода. Побочным преимуществом этого является то, что более простой код с меньшей вероятностью будет укушен ошибкой случайного удаления элемента списка при итерации. Одной из таких парадигм является парадигма понимания списка. Кроме того, понимание списка особенно полезно для предотвращения этой конкретной проблемы, как показано в этой альтернативной реализации приведенного выше кода, которая отлично работает:


Report Page