В каких руководящих принципах PEP 8 вы игнорируете, и к какому из них вы придерживаетесь?

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

Мне было бы интересно узнать, что в PEP 8 (или другие PEP тоже могут быть) люди религиозно придерживаются и почему и что люди находят неудобными или неадекватными.

В моем случае (и на работе вообще) есть только несколько вещей, от которых мы отклоняемся:

  • Подчеркнуть отдельные имена нижнего регистра, я могу увидеть его, так как он будет непременно согласован, но мы склонны использовать lowerCamelCase, даже если он иногда вводит некоторые несоответствия (например, частично или неправильно заглавные аббревиатуры и следующие слова, которые часто сводятся к звонкам). В основном из-за того, что почти все API-интерфейсы мы обычно используем, используйте camelCase (некоторые верхние, некоторые ниже), и потому по какой-то причине мне становится легче читать и, как правило, резервировать символы подчеркивания как разделительные токены или предписанные манипуляции/затенения.

  • Я все еще не могу понять, как PEP предписывает внутренние объекты. new и init Я обычно ухожу прямо под классом без пустых строк, так как я всегда хочу их прочитать прямо там с именем класса и args, методами, которые способствуют одинаковой функциональности в классе (скажем, init, get и set из того же атрибута или набора атрибутов). Я разделяю только одно пространство, и мне нравится три пробела между классами, а два между методами, которые я бы не мысленно не суммировал на карте этого объекта. Это опять же чисто для визуального воздействия и удобочитаемости кода. Я нахожу это очень компактное содержимое внутри управления потоком, и этот вид промежутка между методами и объектами неизменно приводит мой взгляд именно туда, где я хочу, чтобы он продолжал повторное чтение через несколько месяцев после того, как код был припаркован. Он также хорошо реагирует на складывание в моих редакторах по выбору.

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

  • Порядок вещей, таких как импорт, и то, что импортирует, глобалы и т.д. Это действительно отбрасывает меня в файлах с большим объемом импорта, когда они перемешаны или вышли из строя.

  • Пробелы в операторах, особенно когда люди используют вкладки И пытаются выровнять операции присваивания между строками с разной длиной в именах переменных (и, похоже, нет способа убедить тех, кто делает это, что excel ищет кусок кода НЕ опрятно;)).

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

Итак, это мои и аргументы за мои "нарушения" ОПТОСОЗ (некоторые разделяли, некоторые нахмурились коллегами). Мне было бы очень интересно узнать, что делают другие питонисты и не делают в этом отношении.

Ответ 1

Часть "79 символов в строке" - это нонсенс. В их собственном примере показано, как при чтении кода становится нечитаемым:

class Rectangle(Blob):

    def __init__(self, width, height,
                 color='black', emphasis=None, highlight=0):
        if width == 0 and height == 0 and \
           color == 'red' and emphasis == 'strong' or \
           highlight > 100:
            raise ValueError("sorry, you lose")
        if width == 0 and height == 0 and (color == 'red' or
                                           emphasis is None):
            raise ValueError("I don't think so -- values are %s, %s" %
                             (width, height))
        Blob.__init__(self, width, height,
                      color, emphasis, highlight)

Это похоже на попытку прочитать новость, написанную как это.

Терминалы с 80 колонками уже более десяти лет не являются серьезной средой разработки. Когда мне нужно редактировать из искалеченной среды 80x25 в крайнем случае, обертка редактора - это небольшое неудобство; Я не собираюсь калечить свой код во время нормальной разработки, чтобы избежать этого.

120 обтекание колонн отлично подходит для современного развития, и у меня нет проблем с 140. Это руководство устарело, и после него получается уродливый, трудно читаемый код.

Ответ 2

PEP8 говорит, что следует избегать "более одного пробела вокруг оператора присваивания (или другого) для выравнивания его с другим" и "никогда не использовать более одного пробела" вокруг математических операторов, но я не следую этому.

Я часто добавляю "посторонние пробелы", когда соседние строки связаны или очень похожи, но не совсем так:

search_start = (f - f_1/3) * n/fs
search_stop  = (f + f_1/3) * n/fs

b_lpf, a_lpf = filter(N, 2*pi*fc, 'low',  analog=True)
b_hpf, a_hpf = filter(N, 2*pi*fc, 'high', analog=True)

p[x >  1] =                         np.cosh(order * np.arccosh( x[x >  1]))
p[x < -1] = (1 - 2 * (order % 2)) * np.cosh(order * np.arccosh(-x[x < -1]))

b0 =  (1 + cos(w0))/2
b1 = -(1 + cos(w0))

Точно так же раздражает, что я получаю предупреждения стиля кода для массивов чисел, отформатированных таким образом, чтобы они читались так, как будто они обычно форматируются самой библиотекой:

a = array([[-0.198,  0.248, -1.17 , -0.629,  1.378],
           [-1.315,  0.947, -0.736, -1.388,  0.389],
           [ 0.241, -0.98 ,  0.535,  0.951,  1.143],
           [-0.601,  1.286, -0.947,  0.037, -0.864],
           [ 0.178, -0.289, -1.037, -1.453, -0.369]])

PEP8 предпочел бы отформатировать его так, по-видимому, потому что у нас никогда не будет лишних пробелов перед запятыми или после скобок, даже если это улучшает удобочитаемость:

a = array([[-0.198, 0.248, -1.17, -0.629, 1.378],
           [-1.315, 0.947, -0.736, -1.388, 0.389],
           [0.241, -0.98, 0.535, 0.951, 1.143],
           [-0.601, 1.286, -0.947, 0.037, -0.864],
           [0.178, -0.289, -1.037, -1.453, -0.369]])

Ответ 3

PEP8 говорит

Обратите внимание, что наиболее важно то, что "" ", который заканчивает многострочную строку документации, должно находиться на отдельной строке, и предпочтительно перед ней должна стоять пустая строка, например:

"""Return a foobang

Optional plotz says to frobnicate the bizbaz first.

"""

Я нахожу это довольно странным, поскольку он просто "посторонний пробел" и трактует открывающие цитаты иначе, чем закрывающие, без видимой причины.

Обоснование дано в PEP 257:

BDFL рекомендует вставлять пустую строку между последним абзацем в многострочном документировании и его заключительными кавычками, помещая закрывающие кавычки в строку самостоятельно. Таким образом, команда Emacs 'fill-абзац' может быть использована для него.

Emacs, правда? Каждый должен делать странные вещи, чтобы удовлетворить особенности конкретной команды в определенном инструменте редактирования?

Я также думаю, что странно помещать начало строки документации в ту же строку, что и кавычки (не обязательно, но рекомендуется), настаивая на том, чтобы заключительные кавычки были на отдельной строке. Я думаю, что это более логично и должно использоваться как для однострочных, так и для многострочных строк документации:

def foobang(bizbaz, plotz=None):
    """
    Return a foobang

    Optional plotz says to frobnicate the bizbaz first.
    """

    if plotz is not None:
        ...

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

Ответ 4

Я не согласен с этим:

- Imports should usually be on separate lines, e.g.:

    Yes: import os
         import sys

    No:  import sys, os

Я всегда пишу простой импорт вместе. Я не вижу никакого преимущества в написании их всех на отдельных строках: все, что он делает, это добавить раздувание вверху каждого исходного файла и сделать что-то кратким и легким вписать в что-то, что граничит с шаблоном, например. что-то, что так многословно, начинает заманчиво копировать и вставлять из других файлов.

Это мгновенно читаемо и понятно:

import sys, os, time, gc, inspect, math, doctest

Он короткий, легко снимается и легко добавляется. Я использую несколько операторов import, если их слишком много в одной строке, или мне нужен импорт from.

Я также обычно сохраняю стандартный импорт библиотек отдельно от импорта моих собственных модулей и других библиотек, что согласуется с концепцией группировки PEP8.

Ответ 5

Стандарты имеют решающее значение, и PEP 8 - это очень хороший стиль, которым я настаиваю. Единственным ориентиром, с которым я не согласен, является расстояние между математическими операторами. Например, PEP8 настаивает на следующих расстояниях

Without PEP8                           With PEP8                
---------------------------------------------------------------- 
y = sqrt(x**2 + y**2)                  y = sqrt(x ** 2 + y ** 2) 
a*x**3 + b*x**2 + c*x + d              a * x ** 3 + b * x ** 2 + c * x + d 
10**(a*x + b)                          10 ** (a * x + b)  
F = V/(sqrt(g*h) + epsilon)            F = V / (sqrt(g * h) + epsilon) 
a*cos(nx/pi) + b*sin(nx/pi)            a * cos(nx / pi) + b * sin(nx / pi) 

Я пытаюсь соответствовать, но это та область, в которой я борюсь. Кто-нибудь еще чувствует, что интервал PEP8 затрудняет чтение математики?

Update:

PEP8 был исправлен, чтобы рекомендовать форматирование на слева, не поощряя форматирование справа:

Да:

i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
<Не p > Нет:
i=i+1
submitted +=1
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a + b) * (a - b)

Ответ 6

В моих правилах стиля компании вызывается призыв, а не пробелы. PEP 8 намекает, что места предпочтительнее, но мы нашли обратное. Мне нравится видеть код с отступом 4 'пробелов' в VIM, сотрудник предпочитает 8 'пробелов' в Emacs. Использование вкладок позволяет нам настроить наших редакторов на отображение кода по своему усмотрению.

Обратите внимание, что в других языках на языке C наложение фактически является просто форматированием, но в Python отступ является синтаксисом, поэтому мы чувствуем, что indentation level 2 должно быть представлено 2 чего-либо (т.е. вкладки) не 4 или 8 чего-либо (т.е. пробелов).

Выбор символа отступа - это, вероятно, оригинальная война с огнем святого пламени (даже до вспышек VIM/Emacs), поэтому я ожидаю, что вы затушевываетесь, чтобы выразить свое мнение по этому вопросу!

Ответ 7

Я всегда использую 4 пробела, я стараюсь использовать не более 79 символов в строке, а иногда невозможно. Я также использовал импорт, как "import sys, os" в прошлом. В общем, я стараюсь придерживаться PEP 8.

Изменить: также использовать:

def foobar():
    """
    foobar
    """

для документации

Ответ 8

Многострочные условные обозначения и т.д.: PEP-8 явно говорит, что он разбивается после двоичного оператора, а не перед ним. Боюсь, что я не вижу этого. Для меня гораздо больше смысла ломаться до условного, так что в завернутых/продолженных линиях каждая подстрока начинается с условного:

if (condition1 \
        or condition2 \
        or condition3):
    do_something()

Как можно видеть, я также хотел бы добавить дополнительный отступ для sublines, так что они визуально смещены от блока ниже. PEP-8 ничего не говорит об этом (не так ли?), Но в примерах есть подстроки, выровняющиеся с открывающимися круглыми скобками.

Ответ 9

PEP 8 говорит:

Да:

x = 1
y = 2
long_variable = 3
<Не p > Нет:
x             = 1
y             = 2
long_variable = 3

Я обычно следую за ним, но иногда я использую другой вариант для лучшей читаемости:

x =             1
y =             2
long_variable = 3

Ответ 10

"Я допускаю нарушение" - это "если"

PEP8 не говорит о множественном утверждении в одной строке, поэтому, если мы должны это сделать:

if cond:
    actions
    ...

Но когда есть только одно действие, я предпочитаю все в одной строке, например Я предпочитаю:

if a == 0: b = 0

чем:

if a == 0:
     b = 0

Ответ 11

"Проблема" в PEP 8 состоит в том, что он затрагивает области личных предпочтений, которые вызывают у большинства программистов довольно сильные эмоции.

Лично для меня постоянные проблемы были с подчеркиванием и верблюдом в CamelCase. Я также вижу смысл во многих других ответах здесь, и иногда я намеренно нарушаю PEP 8, потому что в этом конкретном случае это просто "имеет смысл".

В моей карьере программиста на Python был момент, когда я просто сдался и повернулся к (используя) PEP 8. Для большинства элементов это было относительно легко, поэтому в настоящее время единственной серьезной проблемой, с которой я сталкиваюсь, является выравнивание столбцов. Этот просто слишком грязный, чтобы повиноваться (хотя я ненавижу в любом случае). В любом случае, из-за того, что я "сдался", мой код стал гораздо более читаемым для моих коллег - и - что удивительно: даже для меня (за исключением выравнивания столбцов, вещь: p).

Я также должен признать, что PEP 8 сделал для самого Python: между 2.x (несовместимым) и 3.x (совместимым), мне гораздо легче "всегда знать", каким будет конкретное имя функции. "Батареи" Python теперь сортируются намного приятнее.

Ответ 12

Когда я пишу крошечные скрипты, я часто просто использую два пробела.

Я всегда использую тот же шаблон для docstrings:

def function():
    """
    Even if it a single line.
    """

Ответ 13

Я использую pylint, http://pypi.python.org/pypi/pylint, это отличный инструмент для того, чтобы ваш код был чистым и читаемым для вас и других разработчиков, ваш код.

Я не затрагиваю все те темы, которые вы сказали, но это очень полезно.

У вас могут быть такие отчеты, как этот:

[email protected]:~/src/fcl/cltools$ pylint numbertoletters.py
No config file found, using default configuration
************* Module numbertoletters
C:  1: Missing docstring
C: 56:es_numero: Missing docstring
C: 56:es_numero: Invalid name "s" (should match [a-z_][a-z0-9_]{2,30}$)
C: 56:es_numero: Invalid name "s" (should match [a-z_][a-z0-9_]{2,30}$)
C: 69:convertnumbertoletters: Empty docstring
C: 90:convertnumbertoletters: Operator not preceded by a space
    numero='%(numero)09d' % {'numero' : int(parte_entera)}
          ^
C: 92:convertnumbertoletters: Comma not followed by a space
    for i in [0,3,6]:
               ^^

W: 69:convertnumbertoletters: Unused argument 'languaje'
C:108:unidades: Empty docstring
C:108:unidades: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:108:unidades: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:112:unidades: Invalid name "u" (should match [a-z_][a-z0-9_]{2,30}$)
C:118:teens: Empty docstring
C:118:teens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:118:teens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:122:teens: Invalid name "t" (should match [a-z_][a-z0-9_]{2,30}$)
C:127:tens: Empty docstring
C:127:tens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:127:tens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:131:tens: Invalid name "t" (should match [a-z_][a-z0-9_]{2,30}$)
C:137:tercia: Empty docstring
C:141:tercia: Operator not preceded by a space
    numero='%(numero)03d' % {'numero' : int(num)}
          ^
C:143:tercia: Invalid name "a" (should match [a-z_][a-z0-9_]{2,30}$)
C:144:tercia: Invalid name "b" (should match [a-z_][a-z0-9_]{2,30}$)
C:145:tercia: Invalid name "c" (should match [a-z_][a-z0-9_]{2,30}$)
C:163:tercia: Operator not followed by a space
                resultado ='veinti '+unidades(c)
                          ^
C:165:tercia: Operator not followed by a space
        elif b >=3 and b <= 9:
               ^^
C:178:tercia: Operator not followed by a space
                resultado ='ciento '+unidades(c)
                          ^
C:192:tercia: Operator not followed by a space
                resultado ='ciento veinti '+unidades(c)
                          ^
C:204:tercia: Operator not preceded by a space
            prefix='quinientos '
                  ^
C:206:tercia: Operator not preceded by a space
            prefix='setecientos '
                  ^
C:208:tercia: Operator not preceded by a space
            prefix='novecientos '
                  ^
C:210:tercia: Operator not preceded by a space
            prefix=unidades(a)+'cientos '
                  ^
R:137:tercia: Too many return statements (23/6)
R:137:tercia: Too many branches (41/12)
R:137:tercia: Too many statements (73/50)


Report
======
141 statements analysed.

Raw metrics
-----------

+----------+-------+------+---------+-----------+
|type      |number |%     |previous |difference |
+==========+=======+======+=========+===========+
|code      |144    |68.25 |NC       |NC         |
+----------+-------+------+---------+-----------+
|docstring |5      |2.37  |NC       |NC         |
+----------+-------+------+---------+-----------+
|comment   |57     |27.01 |NC       |NC         |
+----------+-------+------+---------+-----------+
|empty     |5      |2.37  |NC       |NC         |
+----------+-------+------+---------+-----------+



Statistics by type
------------------

+---------+-------+-----------+-----------+------------+---------+
|type     |number |old number |difference |%documented |%badname |
+=========+=======+===========+===========+============+=========+
|module   |1      |NC         |NC         |0.00        |0.00     |
+---------+-------+-----------+-----------+------------+---------+
|class    |0      |NC         |NC         |0           |0        |
+---------+-------+-----------+-----------+------------+---------+
|method   |0      |NC         |NC         |0           |0        |
+---------+-------+-----------+-----------+------------+---------+
|function |6      |NC         |NC         |0.00        |0.00     |
+---------+-------+-----------+-----------+------------+---------+



Duplication
-----------

+-------------------------+------+---------+-----------+
|                         |now   |previous |difference |
+=========================+======+=========+===========+
|nb duplicated lines      |0     |NC       |NC         |
+-------------------------+------+---------+-----------+
|percent duplicated lines |0.000 |NC       |NC         |
+-------------------------+------+---------+-----------+



Messages by category
--------------------

+-----------+-------+---------+-----------+
|type       |number |previous |difference |
+===========+=======+=========+===========+
|convention |32     |NC       |NC         |
+-----------+-------+---------+-----------+
|refactor   |3      |NC       |NC         |
+-----------+-------+---------+-----------+
|warning    |1      |NC       |NC         |
+-----------+-------+---------+-----------+
|error      |0      |NC       |NC         |
+-----------+-------+---------+-----------+



Messages
--------

+-----------+------------+
|message id |occurrences |
+===========+============+
|C0103      |14          |
+-----------+------------+
|C0322      |6           |
+-----------+------------+
|C0112      |5           |
+-----------+------------+
|C0323      |4           |
+-----------+------------+
|C0111      |2           |
+-----------+------------+
|W0613      |1           |
+-----------+------------+
|R0915      |1           |
+-----------+------------+
|R0912      |1           |
+-----------+------------+
|R0911      |1           |
+-----------+------------+
|C0324      |1           |
+-----------+------------+



Global evaluation
-----------------
Your code has been rated at 7.45/10

I hope it helps.

Я настоятельно рекомендую использовать pylint для оценки вашего кода и придерживаться стандартного способа программирования, особенно в сообществе разработчиков. =)

Надеюсь, это поможет.

Ответ 14

python-mode.el, https://launchpad.net/python-mode

тем временем позволяет настраивать стиль:

M-x настраивать переменную RET py-docstring-style RET

Значение по умолчанию - pep-257-nn

Реализованные стили: DJANGO, ONETWO, PEP-257, PEP-257-NN, SYMMETRIC и NIL.

Значение NIL не будет заботиться о котировках положение и будет обрабатывать докстры, нормальные строки, любые другие значение может привести к одному из следующих типов docstring:

DJANGO:

"""
Process foo, return bar.
"""

"""
Process foo, return bar.

If processing fails throw ProcessingError.
"""

Onetwo:

"""Process foo, return bar."""

"""
Process foo, return bar.

If processing fails throw ProcessingError.

"""

PEP-257:

"""Process foo, return bar."""

"""Process foo, return bar.

If processing fails throw ProcessingError.

"""

PEP-257-NN:

"""Process foo, return bar."""

"""Process foo, return bar.

If processing fails throw ProcessingError.
"""

SYMMETRIC:

"""Process foo, return bar."""

"""
Process foo, return bar.

If processing fails throw ProcessingError.
"""