.. contents:: Содержание
.. _general:
-
Следуй
PEP-8
. Для автоматической проверки и исправления некоторых ошибок можно использовать утилитыpep8
иautopep8
. К сожалению, они проверяют не всё (например, конвенции именования не проверяются). В качестве альтернативы можно использовать статический анализаторflake8
, который помимо стиля проверит наличие некоторых простых ошибок. Плагин для него, проверяющий именование, называетсяpep8-naming
_. -
Располагай импортируемые модули в начале файла.
-
Располагай импортируемые модули в лексикографическом порядке.
.. code:: python
import gzip import sys from collections import defaultdict import io from contextlib import contextmanager import functools from urllib.request import urlopen
import functools import gzip import io import sys from collections import defaultdict from contextlib import contextmanager from urllib.request import urlopen
-
Используй операторы
is
иis not
только для сравнение с синглтонами, например,None
. Исключение: булевые значенияTrue
иFalse
. -
Помни и применяй falsy/truthy семантику. Falsy значения ---
None
,False
, нули0
,0.0
,0j
, пустые строки и байты и все пустые коллекции. Все остальные значения truthy... code:: python
if acc == []: # ...
if len(acc) > 0: # ...
if not acc: # ...
if acc == 0: # ...
-
Не называй переменные именами коллекций. Почти всегда можно подобрать более уместное имя.
-
Не копируй без необходимости.
.. code:: python
set([x**2 for x in range(42)])
for x in list(sorted(xs)): # ...
{x**2 for x in range(42)}
for x in sorted(xs): # ...
-
Не используй
dict.get
и коллекциюdict.keys
для проверки наличия ключа в словаре:.. code:: python
if key in g.keys(): # ...
if not g.get(key, False): # ...
if key in g: # ...
if key not in g: # ...
-
Используй литералы для создания пустых коллекций. Исключение:
set
, литералов пустого множества в Python нет... code:: python
dict(), list(), tuple()
{}, [], ()
.. _PEP-8: https://www.python.org/dev/peps/pep-0008 .. _pep8: https://pypi.python.org/pypi/pep8 .. _autopep8: https://pypi.python.org/pypi/autopep8 .. _flake8: https://pypi.python.org/pypi/flake8 .. _pep8-naming: https://pypi.python.org/pypi/pep8-naming
.. _structure:
-
Не эмулируй оператор
for
, Python --- это не Scala... code:: python
i = 0 while i < n: ... i += 1
for i in range(n): ...
-
Предпочитай итерацию по объекту циклам со счётчиком. Ошибка на 1 в индексе --- это классика. Если же индекс требуется, помни про
enumerate
... code:: python
for i in range(len(xs)) : x = xs[i]
for x in xs: ...
for i, x in enumerate(xs): ...
.. code:: python
for i in range(min(len(xs), len(ys))): f(xs[i], ys[i])
for x, y in zip(xs, ys): f(x, y)
-
Не используй
dict.keys
для итерации по словарю... code:: python
for key in dict.keys(): ...
for key in dict: ...
-
Не используй методы
file.readline
иfile.readlines
для итерации по файлу... code:: python
while True: line = file.readline() ...
for line in file.readlines(): ...
for line in file: ...
-
Не пиши бессмысленных операторов
if
и тернарных операторов... code:: python
if condition: return True else return False
return condition
.. code:: python
if condition: return False else return True
return not condition
.. code:: python
xs = [x for x in xs if predicate] return True if xs else False
xs = [x for x in xs if predicate] return bool(xs)
return any(map(predicate, xs))
.. _functions:
-
Избегай изменяемых значений по умолчанию.
-
Не злоупотребляй функциональными идиомами. Часто генератор списка, множества или словаря понятнее комбинации функций
map
,filter
иzip
... code:: python
list(map(lambda x: x ** 2, filter(lambda x: x % 2 == 1, range(10))))
[x ** 2 for x in range(10) if x % 2 == 1]
-
Не злоупотребляй генераторами коллекций. Часто обычный цикл
for
понятней вложенного генератора. -
Не сворачивай функции с эффектами. Первый аргумент
functools.reduce
не должен изменять состояние имён во внешних областях видимости или значение аккумулятора... code:: python
funtools.reduce(lambda acc, s: acc.update(s), sets,
acc = set() for set in sets: acc.update(set)
-
Избегай бессмысленных анонимных функций.
.. code:: python
map(lambda x: frobnicate(x), xs)
map(frobnicate, xs)
.. code:: python
collections.defaultdict(lambda: [])
collections.defaultdict(list)
.. _decorators:
-
Всегда используй
functools.wraps
илиfunctools.update_wrapper
при написании декоратора.
.. _strings:
-
Используй методы
str.startswith
иstr.endswith
... code:: python
s[:len(p)] == p s.find(p) == len(s) - len(p)
s.startswith(p) s.endswith(p)
-
Используй форматирование строк вместо явных вызовов
str
и конкатенации... code:: python
"(+ " + str(expr1) + " " + str(expr2) + ")"
"(+ {} {})".format(expr1, expr2)
Исключение: приведение к строке одного аргумента.
.. code:: python
"{}".format(value)
str(value)
-
Не усложняй шаблон форматирования без необходимости.
.. code:: python
"(+ {0} {1})" "(+ {expr1} {expr2})"
"(+ {} {})"
-
Помни, что метод
str.format
преобразует аргументы в строку... code:: python
"(+ {} {})".format(str(expr1), str(expr2))
"(+ {} {})".format(expr1, expr2)
.. _classes:
-
Используй
collections.namedtuple
для классов с фиксированным набором неизменяемых полей... code:: python
class Point: def init(self, x, y): self.x = x self.y = y
Point = namedtuple("Point", ["x", "y"])
-
Не вызывай "магические методы" напрямую, если для них есть функция или оператор.
.. code:: python
expr.str() expr.add(other)
str(expr) expr + other
-
Не используй
type
для проверки того, что объект --- экземпляр некоторого класса. Для этого больше подходит функцияisinstance
... code:: python
type(instance) == Point type(instance) is Point
isinstance(instance, Point)
.. _exceptions:
-
Минимизируй размер блоков
try
иwith
. -
Чтобы поймать
любое
исключение используйexcept Exception
, а неexcept BaseException
или простоexcept
. -
Указывай наиболее специфичный тип исключения в блоке
except
... code:: python
try: mapping[key] except Exception: ...
try: mapping[key] except KeyError: ...
-
Наследуй собственные исключения от
Exception
, а не отBaseException
. -
Используй менеджеры контекста вместо
try-finally
... code:: python
handle = open("path/to/file") try: do_something(handle) finally: handle.close()
with open("path/to/file") as handle: do_something(handle)