-
Код должен быть написан так, чтобы не зависеть от разных реализаций языка (PyPy, Jython, IronPython, Pyrex, Psyco и пр.).
Например, не полагайтесь на эффективную реализацию в CPython конкатенации строк в выражениях типа a+=b или a=a+b. Такие инструкции выполняются значительно медленнее в Jython. В критичных к времени выполнения частях программы используйте ''.join() — таким образом склеивание строк будет выполнено за линейное время независимо от реализации python.
-
Сравнения с None должны обязательно выполняться с использованием операторов is или is not, а не с помощью операторов сравнения. Кроме того, не пишите if x, если имеете в виду if x is not None — если, к примеру, при тестировании такая переменная может принять значение другого типа, отличного от None, но при приведении типов может получиться False!
-
При реализации методов сравнения, лучше всего реализовать все 6 операций сравнения (__eq__, __ne__, __lt__, __le__, __gt__, __ge__), чем полагаться на то, что другие программисты будут использовать только конкретный вид сравнения.
Для минимизации усилий можно воспользоваться декораторомfunctools.total_ordering() для реализации недостающих методов.
PEP 207 указывает, что интерпретатор может поменять y > х на х < y, y >= х на х <= y, и может поменять местами аргументы х == y и х != y. Гарантируется, что операции sort() и min() используют оператор <, а max() использует оператор >. Однако, лучше всего осуществить все шесть операций, чтобы не возникало путаницы в других местах.
-
Всегда используйте выражение def, а не присваивание лямбда-выражения к имени.
Правильно:
def f(x): return 2*x
Неправильно:
f = lambda x: 2*x
-
Наследуйте свой класс исключения от Exception, а не от BaseException. Прямое наследование от BaseException зарезервировано для исключений, которые не следует перехватывать.
-
Используйте цепочки исключений соответствующим образом. В Python 3, "raise X from Y" следует использовать для указания явной замены без потери отладочной информации.
Когда намеренно заменяется исключение (использование "raise X" в Python 2 или "raise X from None" в Python 3.3+), проследите, чтобы соответствующая информация передалась в новое исключение (такие, как сохранение имени атрибута при преобразовании KeyError в AttributeError или вложение текста исходного исключения в новом).
-
Когда вы генерируете исключение, пишите raise ValueError('message') вместо старого синтаксиса raise ValueError, message.
Старая форма записи запрещена в python 3.
Такое использование предпочтительнее, потому что из-за скобок не нужно использовать символы для продолжения перенесенных строк, если эти строки длинные или если используется форматирование.
-
Когда код перехватывает исключения, перехватывайте конкретные ошибки вместо простого выражения except:.
К примеру, пишите вот так:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
Простое написание "except:" также перехватит и SystemExit, и KeyboardInterrupt, что породит проблемы, например, сложнее будет завершить программу нажатием control+C. Если вы действительно собираетесь перехватить все исключения, пишите "except Exception:".
Хорошим правилом является ограничение использования "except:", кроме двух случаев:
- Если обработчик выводит пользователю всё о случившейся ошибке; по крайней мере, пользователь будет знать, что произошла ошибка.
- Если нужно выполнить некоторый код после перехвата исключения, а потом вновь "бросить" его для обработки где-то в другом месте. Обычно же лучше пользоваться конструкцией "try...finally".
-
При связывании перехваченных исключений с именем, предпочитайте явный синтаксис привязки, добавленный в Python 2.6:
try:
process_data()
except Exception as exc:
raise DataProcessingFailedError(str(exc))
Это единственный синтаксис, поддерживающийся в Python 3, который позволяет избежать проблем неоднозначности, связанных с более старым синтаксисом на основе запятой.
-
При перехвате ошибок операционной системы, предпочитайте использовать явную иерархию исключений, введенную в Python 3.3, вместо анализа значений errno.
-
Постарайтесь заключать в каждую конструкцию try...except минимум кода, чтобы легче отлавливать ошибки. Опять же, это позволяет избежать замаскированных ошибок.
Правильно:
try:
value = collection[key]
except KeyError:
return key_not_found(key)
else:
return handle_value(value)
Неправильно:
try:
# Здесь много действий!
return handle_value(collection[key])
except KeyError:
# Здесь также перехватится KeyError, который может быть сгенерирован handle_value()
return key_not_found(key)
-
Когда ресурс является локальным на участке кода, используйте выражение withдля того, чтобы после выполнения он был очищен оперативно и надёжно.
-
Менеджеры контекста следует вызывать с помощью отдельной функции или метода, всякий раз, когда они делают что-то другое, чем получение и освобождение ресурсов. Например:
Правильно:
with conn.begin_transaction():
do_stuff_in_transaction(conn)
Неправильно:
with conn:
do_stuff_in_transaction(conn)
Последний пример не дает никакой информации, указывающей на то, что __enter__ и __exit__ делают что-то кроме закрытия соединения после транзакции. Быть явным важно в данном случае.
-
Используйте строковые методы вместо модуля string — они всегда быстрее и имеют тот же API для unicode-строк. Можно отказаться от этого правила, если необходима совместимость с версиями python младше 2.0.
В Python 3 остались только строковые методы.
-
Пользуйтесь ''.startswith() и ''.endswith() вместо обработки срезов строк для проверки суффиксов или префиксов.
startswith() и endswith() выглядят чище и порождают меньше ошибок. Например:
Правильно:
if foo.startswith('bar'):
Неправильно:
if foo[:3] == 'bar':
-
Сравнение типов объектов нужно делать с помощью isinstance(), а не прямым сравнением типов:
Правильно:
if isinstance(obj, int):
Неправильно:
if type(obj) is type(1):
Когда вы проверяете, является ли объект строкой, обратите внимание на то, что строка может быть unicode-строкой. В python 2 у str и unicode есть общий базовый класс, поэтому вы можете написать:
if isinstance(obj, basestring):
Отметим, что в Python 3, unicode и basestring больше не существуют (есть только str) и bytes больше не является своего рода строкой (это последовательность целых чисел).
-
Для последовательностей (строк, списков, кортежей) используйте тот факт, что пустая последовательность есть false:
Правильно:
if not seq:
if seq:
Неправильно:
if len(seq)
if not len(seq)
-
Не пользуйтесь строковыми константами, которые имеют важные пробелы в конце — они невидимы, а многие редакторы (а теперь и reindent.py) обрезают их.
-
Не сравнивайте логические типы с True и False с помощью ==:
Правильно:
if greeting:
Неправильно:
if greeting == True:
Совсем неправильно:
if greeting is True: