Меню

Indentation is not a multiple of four python ошибка

@s0undt3ch

Consider the example:

def foo():
    a = True  # this is a properly indented comment
              # isn't it?

And here’s what pep8 reports.

$ pep8 /tmp/test.py
/tmp/test.py:3:15: E111 indentation is not a multiple of four
/tmp/test.py:3:15: E113 unexpected indentation

I personally consider both an error in «judgement»

@s0undt3ch

Shouldn’t we only be getting E113?

@sigmavirus24

@s0undt3ch please review the document PEP 8, specifically the inline comment section. It says «Use inline comments sparingly» and the examples it gives contain the comment to the same line. If your comment will take more than a line it should be placed before the line you’re commenting. There is no error in judgment here.

I’m not sure which error you should be getting (if in fact you should only be receiving one) because the 3rd line in your example is indeed not indented with a multiple of 4 spaces and it is in fact unexpected indentation.

@florentx

I agree with @sigmavirus24 analysis. 👍

In addition, if you want to circumvent this check, it will be easier in the next release.
I’ve accepted enhancement #274 which is similar to your report: indentation of comments will report E114/E115/E116 instead of E111/E112/E113.

@s0undt3ch

On 8 de Junho de 2014 8:36:00 WEST, Florent Xicluna notifications@github.com wrote:

I agree with @sigmavirus24 analysis. 👍

In addition, if you want to circumvent this check, it will be easier in
the next release.
I’ve accepted enhancement #274 which is similar to your report:
indentation of comments will report E114/E115/E116 instead of
E111/E112/E113.


Reply to this email directly or view it on GitHub:
#300 (comment)

That ticket was created by me 😄

OK, as long as I’m able to ignore these IDs…
Pedro Algarvio @ Phone

@ghost

Ooh! Maybe we could add a check for inline comments!

@sigmavirus24

@ghost

@sigmavirus24 Nevermind, I thought I was commenting in a different window 👍

@IanLee1521

Looks like this was probably resolved with the the referenced release.

I’m re-formatting a Python script using notepad++, but some lines are not indented by 4 (or 8, 12, 16, etc.) spaces.

So I need to match consecutive leading white-spaces (i.e. indentation at beginning of each line), which are NOT in multiple of 4, i.e. spaces in number of 1, 2, 3, 5, 6, 7, 9, 10, 11, etc.

e.g.

>>>   a = 1      # match this, as there're 3 spaces at the beginning
>>>       b = a  # match this too, as indent by 7 spaces
>>>    c = 2     # but not this, since it's indented exactly by 4 spaces
>>>        d = c # not this either, since indented by 8 spaces

I was able to match spaces in multiple of 4 using something like:

^( {16}| {12}| {8}| {4})

then I tried to match the opposite of this with something like:

^[^( {16}| {12}| {8}| {4})]

but it only matches empty line or line start with a character, not what I want.

I’m a complete newbie to regex, but I’ve searched for hours with no luck. I know I could always match with all the non-multiple-of-4 numbers listed, but I was hoping someone could help and provide a less-cumbersome method.

Thanks.

Update 1

using regex (@user2864740)

^(?:s{4})*s{1,3}S

or (@alpha bravo)

^(?!(s{4})+S)(.*)

matches non-multiple-of-4 indents, as well as empty line(s) with 4 (8, 16, etc.) spaces and the first character of the first non-empty line following them.

e.g. (on regex101.com)

How to avoid matching these situations described in the example above?

PEP 8 — руководство по написанию кода на Python

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

PEP 8 создан на основе рекомендаций Гуидо ван Россума с добавлениями от Барри. Если где-то возникал конфликт, мы выбирали стиль Гуидо. И, конечно, этот PEP может быть неполным (фактически, он, наверное, никогда не будет закончен).

Ключевая идея Гуидо такова: код читается намного больше раз, чем пишется. Собственно, рекомендации о стиле написания кода направлены на то, чтобы улучшить читаемость кода и сделать его согласованным между большим числом проектов. В идеале, весь код будет написан в едином стиле, и любой сможет легко его прочесть.

Это руководство о согласованности и единстве. Согласованность с этим руководством очень важна. Согласованность внутри одного проекта еще важнее. А согласованность внутри модуля или функции — самое важное. Но важно помнить, что иногда это руководство неприменимо, и понимать, когда можно отойти от рекомендаций. Когда вы сомневаетесь, просто посмотрите на другие примеры и решите, какой выглядит лучше.

Две причины для того, чтобы нарушить данные правила:

  1. Когда применение правила сделает код менее читаемым даже для того, кто привык читать код, который следует правилам.
  2. Чтобы писать в едином стиле с кодом, который уже есть в проекте и который нарушает правила (возможно, в силу исторических причин) — впрочем, это возможность переписать чужой код.

Содержание

Внешний вид кода

Отступы

Используйте 4 пробела на каждый уровень отступа.

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

Закрывающие круглые/квадратные/фигурные скобки в многострочных конструкциях могут находиться под первым непробельным символом последней строки списка, например:

либо быть под первым символом строки, начинающей многострочную конструкцию:

Табуляция или пробелы?

Пробелы — самый предпочтительный метод отступов.

Табуляция должна использоваться только для поддержки кода, написанного с отступами с помощью табуляции.

Python 3 запрещает смешивание табуляции и пробелов в отступах.

Python 2 пытается преобразовать табуляцию в пробелы.

Когда вы вызываете интерпретатор Python 2 в командной строке с параметром -t, он выдает предупреждения (warnings) при использовании смешанного стиля в отступах, а запустив интерпретатор с параметром -tt, вы получите в этих местах ошибки (errors). Эти параметры очень рекомендуются!

Максимальная длина строки

Ограничьте длину строки максимум 79 символами.

Для более длинных блоков текста с меньшими структурными ограничениями (строки документации или комментарии), длину строки следует ограничить 72 символами.

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

Некоторые команды предпочитают большую длину строки. Для кода, поддерживающегося исключительно или преимущественно этой группой, в которой могут прийти к согласию по этому вопросу, нормально увеличение длины строки с 80 до 100 символов (фактически увеличивая максимальную длину до 99 символов), при условии, что комментарии и строки документации все еще будут 72 символа.

Стандартная библиотека Python консервативна и требует ограничения длины строки в 79 символов (а строк документации/комментариев в 72).

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

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

Ещё один случай — assert.

Сделайте правильные отступы для перенесённой строки. Предпочтительнее вставить перенос строки после логического оператора, но не перед ним. Например:

Пустые строки

Отделяйте функции верхнего уровня и определения классов двумя пустыми строками.

Определения методов внутри класса разделяются одной пустой строкой.

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

Используйте пустые строки в функциях, чтобы указать логические разделы.

Python расценивает символ control+L как незначащий (whitespace), и вы можете использовать его, потому что многие редакторы обрабатывают его как разрыв страницы — таким образом логические части в файле будут на разных страницах. Однако, не все редакторы распознают control+L и могут на его месте отображать другой символ.

Кодировка исходного файла

Кодировка Python должна быть UTF-8 (ASCII в Python 2).

Файлы в ASCII (Python 2) или UTF-8 (Python 3) не должны иметь объявления кодировки.

В стандартной библиотеке, нестандартные кодировки должны использоваться только для целей тестирования, либо когда комментарий или строка документации требует упомянуть имя автора, содержащего не ASCII символы; в остальных случаях использование x, u, U или N — наиболее предпочтительный способ включить не ASCII символы в строковых литералах.

Начиная с версии python 3.0 в стандартной библиотеке действует следующее соглашение: все идентификаторы обязаны содержать только ASCII символы, и означать английские слова везде, где это возможно (во многих случаях используются сокращения или неанглийские технические термины). Кроме того, строки и комментарии тоже должны содержать лишь ASCII символы. Исключения составляют: (а) test case, тестирующий не-ASCII особенности программы, и (б) имена авторов. Авторы, чьи имена основаны не на латинском алфавите, должны транслитерировать свои имена в латиницу.

Проектам с открытым кодом для широкой аудитории также рекомендуется использовать это соглашение.

Импорты

Каждый импорт, как правило, должен быть на отдельной строке.

В то же время, можно писать так:

Импорты всегда помещаются в начале файла, сразу после комментариев к модулю и строк документации, и перед объявлением констант.

Импорты должны быть сгруппированы в следующем порядке:

  1. импорты из стандартной библиотеки
  2. импорты сторонних библиотек
  3. импорты модулей текущего проекта

Вставляйте пустую строку между каждой группой импортов.

Указывайте спецификации __all__ после импортов.

Рекомендуется абсолютное импортирование, так как оно обычно более читаемо и ведет себя лучше (или, по крайней мере, даёт понятные сообщения об ошибках) если импортируемая система настроена неправильно (например, когда каталог внутри пакета заканчивается на sys.path):

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

В стандартной библиотеке следует избегать сложной структуры пакетов и всегда использовать абсолютные импорты.

Неявные относительно импорты никогда не должны быть использованы, и были удалены в Python 3.

Когда вы импортируете класс из модуля, вполне можно писать вот так:

Если такое написание вызывает конфликт имен, тогда пишите:

И используйте «myclass.MyClass» и «foo.bar.yourclass.YourClass».

Шаблоны импортов (from import *) следует избегать, так как они делают неясным то, какие имена присутствуют в глобальном пространстве имён, что вводит в заблуждение как читателей, так и многие автоматизированные средства. Существует один оправданный пример использования шаблона импорта, который заключается в опубликовании внутреннего интерфейса как часть общественного API (например, переписав реализацию на чистом Python в модуле акселератора (и не будет заранее известно, какие именно функции будут перезаписаны).

Пробелы в выражениях и инструкциях

Избегайте использования пробелов в следующих ситуациях:

Непосредственно внутри круглых, квадратных или фигурных скобок.

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

Сразу перед открывающей скобкой, после которой начинается список аргументов при вызове функции:

Сразу перед открывающей скобкой, после которой следует индекс или срез:

Использование более одного пробела вокруг оператора присваивания (или любого другого) для того, чтобы выровнять его с другим:

Другие рекомендации

Всегда окружайте эти бинарные операторы одним пробелом с каждой стороны: присваивания (=, +=, -= и другие), сравнения (==, <, >, !=, <>, <=, >=, in, not in, is, is not), логические (and, or, not).

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

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

Не используйте составные инструкции (несколько команд в одной строке).

Иногда можно писать тело циклов while, for или ветку if в той же строке, если команда короткая, но если команд несколько, никогда так не пишите. А также избегайте длинных строк!

Комментарии

Комментарии, противоречащие коду, хуже, чем отсутствие комментариев. Всегда исправляйте комментарии, если меняете код!

Комментарии должны являться законченными предложениями. Если комментарий — фраза или предложение, первое слово должно быть написано с большой буквы, если только это не имя переменной, которая начинается с маленькой буквы (никогда не изменяйте регистр переменной!).

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

Ставьте два пробела после точки в конце предложения.

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

Блоки комментариев

Блок комментариев обычно объясняет код (весь, или только некоторую часть), идущий после блока, и должен иметь тот же отступ, что и сам код. Каждая строчка такого блока должна начинаться с символа # и одного пробела после него (если только сам текст комментария не имеет отступа).

Абзацы внутри блока комментариев разделяются строкой, состоящей из одного символа #.

«Встрочные» комментарии

Старайтесь реже использовать подобные комментарии.

Такой комментарий находится в той же строке, что и инструкция. «Встрочные» комментарии должны отделяться по крайней мере двумя пробелами от инструкции. Они должны начинаться с символа # и одного пробела.

Комментарии в строке с кодом не нужны и только отвлекают от чтения, если они объясняют очевидное. Не пишите вот так:

Впрочем, такие комментарии иногда полезны:

Строки документации

Пишите документацию для всех публичных модулей, функций, классов, методов. Строки документации необязательны для приватных методов, но лучше написать, что делает метод. Комментарий нужно писать после строки с def.

PEP 257 объясняет, как правильно и хорошо документировать. Заметьте, очень важно, чтобы закрывающие кавычки стояли на отдельной строке. А еще лучше, если перед ними будет ещё и пустая строка, например:

Для однострочной документации можно оставить закрывающие кавычки на той же строке.

Контроль версий

Если вам нужно использовать Subversion, CVS или RCS в ваших исходных кодах, делайте вот так:

Вставляйте эти строки после документации модуля перед любым другим кодом и отделяйте их пустыми строками по одной до и после.

Соглашения по именованию

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

Главный принцип

Имена, которые видны пользователю как часть общественного API должны следовать конвенциям, которые отражают использование, а не реализацию.

Описание: Стили имен

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

Обычно различают следующие стили:

  • b (одиночная маленькая буква)
  • B (одиночная заглавная буква)
  • lowercase (слово в нижнем регистре)
  • lower_case_with_underscores (слова из маленьких букв с подчеркиваниями)
  • UPPERCASE (заглавные буквы)
  • UPPERCASE_WITH_UNDERSCORES (слова из заглавных букв с подчеркиваниями)
  • CapitalizedWords (слова с заглавными буквами, или CapWords, или CamelCase). Замечание: когда вы используете аббревиатуры в таком стиле, пишите все буквы аббревиатуры заглавными — HTTPServerError лучше, чем HttpServerError.
  • mixedCase (отличается от CapitalizedWords тем, что первое слово начинается с маленькой буквы)
  • Capitalized_Words_With_Underscores (слова с заглавными буквами и подчеркиваниями — уродливо!)

Ещё существует стиль, в котором имена, принадлежащие одной логической группе, имеют один короткий префикс. Этот стиль редко используется в python, но мы упоминаем его для полноты. Например, функция os.stat() возвращает кортеж, имена в котором традиционно имеют вид st_mode, st_size, st_mtime и так далее. (Так сделано, чтобы подчеркнуть соответствие этих полей структуре системных вызовов POSIX, что помогает знакомым с ней программистам).

В библиотеке X11 используется префикс Х для всех public-функций. В python этот стиль считается излишним, потому что перед полями и именами методов стоит имя объекта, а перед именами функций стоит имя модуля.

В дополнение к этому, используются следующие специальные формы записи имен с добавлением символа подчеркивания в начало или конец имени:

_single_leading_underscore: слабый индикатор того, что имя используется для внутренних нужд. Например, from M import * не будет импортировать объекты, чьи имена начинаются с символа подчеркивания.

single_trailing_underscore_: используется по соглашению для избежания конфликтов с ключевыми словами языка python, например:

__double_leading_underscore: изменяет имя атрибута класса, то есть в классе FooBar поле __boo становится _FooBar__boo.

__double_leading_and_trailing_underscore__ (двойное подчеркивание в начале и в конце имени): магические методы или атрибуты, которые находятся в пространствах имен, управляемых пользователем. Например, __init__, __import__ или __file__. Не изобретайте такие имена, используйте их только так, как написано в документации.

Предписания: соглашения по именованию

Имена, которых следует избегать

Никогда не используйте символы l (маленькая латинская буква «эль»), O (заглавная латинская буква «о») или I (заглавная латинская буква «ай») как однобуквенные идентификаторы.

В некоторых шрифтах эти символы неотличимы от цифры один и нуля. Если очень нужно l, пишите вместо неё заглавную L.

Имена модулей и пакетов

Модули должны иметь короткие имена, состоящие из маленьких букв. Можно использовать символы подчеркивания, если это улучшает читабельность. То же самое относится и к именам пакетов, однако в именах пакетов не рекомендуется использовать символ подчёркивания.

Так как имена модулей отображаются в имена файлов, а некоторые файловые системы являются нечувствительными к регистру символов и обрезают длинные имена, очень важно использовать достаточно короткие имена модулей — это не проблема в Unix, но, возможно, код окажется непереносимым в старые версии Windows, Mac, или DOS.

Когда модуль расширения, написанный на С или C++, имеет сопутствующий python-модуль (содержащий интерфейс высокого уровня), С/С++ модуль начинается с символа подчеркивания, например, _socket.

Имена классов

Имена классов должны обычно следовать соглашению CapWords.

Вместо этого могут использоваться соглашения для именования функций, если интерфейс документирован и используется в основном как функции.

Обратите внимание, что существуют отдельные соглашения о встроенных именах: большинство встроенных имен — одно слово (либо два слитно написанных слова), а соглашение CapWords используется только для именования исключений и встроенных констант.

Имена исключений

Так как исключения являются классами, к исключениям применяется стиль именования классов. Однако вы можете добавить Error в конце имени (если, конечно, исключение действительно является ошибкой).

Имена глобальных переменных

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

Добавляйте в модули, которые написаны так, чтобы их использовали с помощью from M import *, механизм __all__, чтобы предотвратить экспортирование глобальных переменных. Или же, используйте старое соглашение, добавляя перед именами таких глобальных переменных один символ подчеркивания (которым вы можете обозначить те глобальные переменные, которые используются только внутри модуля).

Имена функций

Имена функций должны состоять из маленьких букв, а слова разделяться символами подчеркивания — это необходимо, чтобы увеличить читабельность.

Стиль mixedCase допускается в тех местах, где уже преобладает такой стиль, для сохранения обратной совместимости.

Аргументы функций и методов

Всегда используйте self в качестве первого аргумента метода экземпляра объекта.

Всегда используйте cls в качестве первого аргумента метода класса.

Если имя аргумента конфликтует с зарезервированным ключевым словом python, обычно лучше добавить в конец имени символ подчеркивания, чем исказить написание слова или использовать аббревиатуру. Таким образом, class_ лучше, чем clss. (Возможно, хорошим вариантом будет подобрать синоним).

Имена методов и переменных экземпляров классов

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

Используйте один символ подчёркивания перед именем для непубличных методов и атрибутов.

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

Python искажает эти имена: если класс Foo имеет атрибут с именем __a, он не может быть доступен как Foo.__a. (Настойчивый пользователь все еще может получить доступ, вызвав Foo._Foo__a.) Вообще, два ведущих подчеркивания должны использоваться только для того, чтобы избежать конфликтов имен с атрибутами классов, предназначенных для наследования.

Примечание: есть некоторые разногласия по поводу использования __ имена (см. ниже).

Константы

Константы обычно объявляются на уровне модуля и записываются только заглавными буквами, а слова разделяются символами подчеркивания. Например: MAX_OVERFLOW, TOTAL.

Проектирование наследования

Обязательно решите, каким должен быть метод класса или экземпляра класса (далее — атрибут) — публичный или непубличный. Если вы сомневаетесь, выберите непубличный атрибут. Потом будет проще сделать его публичным, чем наоборот.

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

Мы не используем термин «приватный атрибут», потому что на самом деле в python таких не бывает.

Другой тип атрибутов классов принадлежит так называемому API подклассов (в других языках они часто называются protected). Некоторые классы проектируются так, чтобы от них наследовали другие классы, которые расширяют или модифицируют поведение базового класса. Когда вы проектируете такой класс, решите и явно укажите, какие атрибуты являются публичными, какие принадлежат API подклассов, а какие используются только базовым классом.

Теперь сформулируем рекомендации:

Открытые атрибуты не должны иметь в начале имени символа подчеркивания.

Если имя открытого атрибута конфликтует с ключевым словом языка, добавьте в конец имени один символ подчеркивания. Это более предпочтительно, чем аббревиатура или искажение написания (однако, у этого правила есть исключение — аргумента, который означает класс, и особенно первый аргумент метода класса (class method) должен иметь имя cls).

Назовите простые публичные атрибуты понятными именами и не пишите сложные методы доступа и изменения (accessor/mutator, get/set, — прим. перев.) Помните, что в python очень легко добавить их потом, если потребуется. В этом случае используйте свойства (properties), чтобы скрыть функциональную реализацию за синтаксисом доступа к атрибутам.

Примечание 1: Свойства (properties) работают только в классах нового стиля (в Python 3 все классы являются таковыми).

Примечание 2: Постарайтесь избавиться от побочных эффектов, связанным с функциональным поведением; впрочем, такие вещи, как кэширование, вполне допустимы.

Примечание 3: Избегайте использования вычислительно затратных операций, потому что из-за записи с помощью атрибутов создается впечатление, что доступ происходит (относительно) быстро.

Если вы планируете класс таким образом, чтобы от него наследовались другие классы, но не хотите, чтобы подклассы унаследовали некоторые атрибуты, добавьте в имена два символа подчеркивания в начало, и ни одного — в конец. Механизм изменения имен в python сработает так, что имя класса добавится к имени такого атрибута, что позволит избежать конфликта имен с атрибутами подклассов.

Примечание 1: Будьте внимательны: если подкласс будет иметь то же имя класса и имя атрибута, то вновь возникнет конфликт имен.

Примечание 2: Механизм изменения имен может затруднить отладку или работу с __getattr__(), однако он хорошо документирован и легко реализуется вручную.

Примечание 3: Не всем нравится этот механизм, поэтому старайтесь достичь компромисса между необходимостью избежать конфликта имен и возможностью доступа к этим атрибутам.

Общие рекомендации

Код должен быть написан так, чтобы не зависеть от разных реализаций языка (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, а не присваивание лямбда-выражения к имени.

Наследуйте свой класс исключения от 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:.

К примеру, пишите вот так:

Простое написание «except:» также перехватит и SystemExit, и KeyboardInterrupt, что породит проблемы, например, сложнее будет завершить программу нажатием control+C. Если вы действительно собираетесь перехватить все исключения, пишите «except Exception:».

Хорошим правилом является ограничение использования «except:», кроме двух случаев:

  1. Если обработчик выводит пользователю всё о случившейся ошибке; по крайней мере, пользователь будет знать, что произошла ошибка.
  2. Если нужно выполнить некоторый код после перехвата исключения, а потом вновь «бросить» его для обработки где-то в другом месте. Обычно же лучше пользоваться конструкцией «try. finally».

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

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

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

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

Когда ресурс является локальным на участке кода, используйте выражение with для того, чтобы после выполнения он был очищен оперативно и надёжно.

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

Последний пример не дает никакой информации, указывающей на то, что __enter__ и __exit__ делают что-то кроме закрытия соединения после транзакции. Быть явным важно в данном случае.

Используйте строковые методы вместо модуля string — они всегда быстрее и имеют тот же API для unicode-строк. Можно отказаться от этого правила, если необходима совместимость с версиями python младше 2.0.

В Python 3 остались только строковые методы.

Пользуйтесь ».startswith() и ».endswith() вместо обработки срезов строк для проверки суффиксов или префиксов.

startswith() и endswith() выглядят чище и порождают меньше ошибок. Например:

Сравнение типов объектов нужно делать с помощью isinstance(), а не прямым сравнением типов:

Когда вы проверяете, является ли объект строкой, обратите внимание на то, что строка может быть unicode-строкой. В python 2 у str и unicode есть общий базовый класс, поэтому вы можете написать:

Отметим, что в Python 3, unicode и basestring больше не существуют (есть только str) и bytes больше не является своего рода строкой (это последовательность целых чисел).

Для последовательностей (строк, списков, кортежей) используйте тот факт, что пустая последовательность есть false:

indentation is not a multiple of four on comments #300

The text was updated successfully, but these errors were encountered:

sigmavirus24 commented Jun 7, 2014

@s0undt3ch please review the document PEP 8, specifically the inline comment section. It says «Use inline comments sparingly» and the examples it gives contain the comment to the same line. If your comment will take more than a line it should be placed before the line you’re commenting. There is no error in judgment here.

I’m not sure which error you should be getting (if in fact you should only be receiving one) because the 3rd line in your example is indeed not indented with a multiple of 4 spaces and it is in fact unexpected indentation.

florentx commented Jun 8, 2014

I agree with @sigmavirus24 analysis.

In addition, if you want to circumvent this check, it will be easier in the next release.
I’ve accepted enhancement #274 which is similar to your report: indentation of comments will report E114/E115/E116 instead of E111/E112/E113 .

s0undt3ch commented Jun 8, 2014

On 8 de Junho de 2014 8:36:00 WEST, Florent Xicluna notifications@github.com wrote:

I agree with @sigmavirus24 analysis.

In addition, if you want to circumvent this check, it will be easier in
the next release.
I’ve accepted enhancement #274 which is similar to your report:
indentation of comments will report E114/E115/E116 instead of
E111/E112/E113 .

Reply to this email directly or view it on GitHub:
#300 (comment)

That ticket was created by me

OK, as long as I’m able to ignore these IDs.
Pedro Algarvio @ Phone

ghost commented Jun 11, 2014

Ooh! Maybe we could add a check for inline comments!

sigmavirus24 commented Jun 11, 2014

ghost commented Jun 11, 2014

@sigmavirus24 Nevermind, I thought I was commenting in a different window

IanLee1521 commented Feb 25, 2016

Looks like this was probably resolved with the the referenced release.

You can’t perform that action at this time.

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.

Python: надежная защита от потери запятой в вертикальном списке строк

Списки строк в программах встречаются часто. Для удобства чтения их не менее часто форматируют вертикально, по одной строке. И есть в такой конструкции уязвимость — если при изменении списка потерять запятую между элементами, то многие языки просто склеют строки слева и справа от пропущенной запятой — в результате получится валидный с точки зрения языка список, в котором на один элемент меньше чем ожидается и один элемент имеет некорректное значение. Есть много способов профилактики этой проблемы, но недавно на stackoverflow мне показали настолько простой и надежный способ, что я просто не могу им не поделиться.

Демонстрация проблемы

Сначала посмотрим визуально как выглядит проблема. Типичный вертикальный список, в котором потеряна запятая:

Если внимательно посмотреть, между строками «italian» и «spanish» пропущена запятая. Но при запуске такой программы ошибок не будет: Python просто склеит строки «italian» и «spanish», превратив наш список вот в это:

На практике такие опечатки встречатся не то чтобы очень часто — но к багам приводят знатным и долгоотлаживаемым.

Как бороться по-феншую

В соответствии c феншуем, данный ряд проблем необходимо отсекать статическими анализаторами кода типа lint в рамках автобилда. Но тут есть неприятный нюанс — pylint по умолчанию не считает пример выше ошибочным. Следовательно, придется его долго и муторно настраивать, потому как есть много вполне корректного кода, где строки склеиваются по делу и никаких запятых быть не должно. Плюс не у всех настроена связка pylint + autobuild, а поднимать полноценный continous integration с нуля только ради указанной проблемы не всегда с руки.

Как борются на практике

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

Минусом первого способа является то, что он защищает только от ошибок копипасты — но не защищает от опечаток и результатов применения к тексту скриптов.

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

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

Новый способ

Был подсказан гуру на stackoverflow. Не могу сказать что он особо красив или удобен — но он прост и надежен. При потере запятой случается ошибка выполнения скрипта. Способ заключется в окружении каждой строки круглыми скобками — это превращает epression типа строка в сложносоставной expression, который уже склеивать нельзя:

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

Descriptions and examples for each of the rules in Flake8 (pyflakes, pycodestyle, and mccabe).

pycodestyle

E101 Indentation contains mixed spaces and tabs
E111 Indentation is not a multiple of four
E112 Expected an indented block
E113 Unexpected indentation
E114 Indentation is not a multiple of four (comment)
E115 Expected an indented block (comment)
E116 Unexpected indentation (comment)
E121 Continuation line under-indented for hanging indent
E122 Continuation line missing indentation or outdented
E123 Closing bracket does not match indentation of opening bracket’s line
E124 Closing bracket does not match visual indentation
E125 Continuation line with same indent as next logical line
E126 Continuation line over-indented for hanging indent
E127 Continuation line over-indented for visual indent
E128 Continuation line under-indented for visual indent
E129 Visually indented line with same indent as next logical line
E131 Continuation line unaligned for hanging indent
E133 Closing bracket is missing indentation
E201 Whitespace after ‘(‘
E202 Whitespace before ‘)’
E203 Whitespace before ‘:’
E211 Whitespace before ‘(‘
E221 Multiple spaces before operator
E222 Multiple spaces after operator
E223 Tab before operator
E224 Tab after operator
E225 Missing whitespace around operator
E226 Missing whitespace around arithmetic operator
E227 Missing whitespace around bitwise or shift operator
E228 Missing whitespace around modulo operator
E231 Missing whitespace after ‘,’, ‘;’, or ‘:’
E241 Multiple spaces after ‘,’
E242 Tab after ‘,’
E251 Unexpected spaces around keyword / parameter equals
E261 At least two spaces before inline comment
E262 Inline comment should start with ‘# ‘
E265 Block comment should start with ‘# ‘
E266 Too many leading ‘#’ for block comment
E271 Multiple spaces after keyword
E272 Multiple spaces before keyword
E273 Tab after keyword
E274 Tab before keyword
E275 Missing whitespace after keyword
E301 Expected 1 blank line, found 0
E302 Expected 2 blank lines, found 0
E303 Too many blank lines (3)
E304 Blank lines found after function decorator
E305 Expected 2 blank lines after end of function or class
E401 Multiple imports on one line
E402 Module level import not at top of file
E501 Line too long (82 > 79 characters)
E502 The backslash is redundant between brackets
E701 Multiple statements on one line (colon)
E702 Multiple statements on one line (semicolon)
E703 Statement ends with a semicolon
E704 Multiple statements on one line (def)
E711 Comparison to none should be ‘if cond is none:’
E712 Comparison to true should be ‘if cond is true:’ or ‘if cond:’
E713 Test for membership should be ‘not in’
E714 Test for object identity should be ‘is not’
E721 Do not compare types, use ‘isinstance()’
E731 Do not assign a lambda expression, use a def
E741 Do not use variables named ‘l’, ‘o’, or ‘i’
E742 Do not define classes named ‘l’, ‘o’, or ‘i’
E743 Do not define functions named ‘l’, ‘o’, or ‘i’
W191 Indentation contains tabs
W291 Trailing whitespace
W292 No newline at end of file
W293 Blank line contains whitespace
W391 Blank line at end of file
W503 Line break occurred before a binary operator
W504 Line break occurred after a binary operator
W601 .has_key() is deprecated, use ‘in’
W602 Deprecated form of raising exception
W603 ‘<>’ is deprecated, use ‘!=’
W604 Backticks are deprecated, use ‘repr()’
W605 invalid escape sequence ‘x’

pyflakes

F401 Module imported but unused
F402 Import module from line n shadowed by loop variable
F403 ‘from module import *’ used; unable to detect undefined names
F404 Future import(s) name after other statements
F405 Name may be undefined, or defined from star imports: module
F811 Redefinition of unused name from line n
F812 List comprehension redefines name from line n
F821 Undefined name name
F822 Undefined name name in __all__
F823 Local variable name … referenced before assignment
F831 Duplicate argument name in function definition
F841 Local variable name is assigned to but never used

mccabe

One of Guido’s key insights is that code is read much more often than it is written. – PEP8

There should be one—and preferably only one—obvious way to do it. – The Zen of Python

Any fool can write code that a computer can understand. Good programmers write code that humans can understand. – Martin Fowler

After Julian’s two recent style posts on indentation and naming convention a nice follow-up is PEP8, the Style Guide for Python Code. Also a comment on Twitter caught my eye stating that even book authors do not always follow PEP8!

Why bother?

I think everybody writing code in Python should become familiar with PEP8 and use its guidelines rather sooner than later.

It leads to more readable code which saves brain cycles and better maintainable code (= fewer bug).

Also sharing a common coding style makes it easier to collaborate with others in the Python community.

Of course there can be exceptions to the rule, PEP8 states: “do not break backwards compatibility just to comply with this PEP!” – Raymond Hettinger did a great talk on this: Beyond PEP 8

Summary of the guidelines

A read that is aimed for ‘5 min’ cannot have all, so I just summarize what I think is important, read the full spec for details:

  • Use 4 spaces per indentation level. Use spaces, not tabs. See our post for more on this, including recommended .vimrc settings. Overall watch your use of whitespace: this takes practice, but becomes habit/ automatic over time.

  • Limit all lines to a maximum of 79 characters. Usually I have a script.py and test_script.py open, vertically alligned (vi -O file1 file2), keeping lines short makes this very convenient.

  • Imports I) be as specific as possible with your imports:

    # don't do:
    from time import *
    (unless needed, then use the __all__ mechanism to prevent exporting globals)
    # do:
    from time import time
    # or:
    import time
    # then prepends each method with module name:
    time.time()
    
  • Imports II) absolute imports are recommended:

    from mypkg.sibling import example
    # over
    from .sibling import example
    
  • Imports III) split imports in stdlib – third party – application/library specific. For example our twitter bot followed this convention:

    # stdlib
    import datetime
    import logging
    import time
    
    # pip installed
    import feedparser
    import tweepy
    
    # app modules
    from config import ...
    ...
    
  • Comments that contradict the code are worse than no comments, so keep them up2date. Use inline comments sparingly. Of course good code is mostly self-documenting.

  • Use docstrings, they are a great aid for auto-documenting your project with tools like Sphinx. Here is the recommended syntax:

    """Multi-line docstrings consist of a summary line just like a one-line docstring
    
    Followed by a blank line, followed by a more elaborate description.
    """
    
  • Naming:

    • Non-public methods and instance variables start with a leading underscore: _helper_method(), although not enforced by the compiler, the reader knows this is an internal method, not to be called from outside of the class.

    • If you need to use a Python keyword append an underscore: str_ = ‘bob’

    • You probably want to avoid single-char variables all together, but if you use them never use these easily confused chars: ‘l’ (lowercase letter el), ‘O’ (uppercase letter oh), or ‘I’ (uppercase letter eye).

    • Use CapWords for class names.

    • Use short, all-lowercase names for modules.

    • Use lowercase and underscores for method names.

    • Constants are all uppercase, in our Twitter bot example: CONSUMER_KEY, CONSUMER_SECRET, etc.

  • Programming Recommendations has some great tips: use ”.join(list) instead of string concatenation which is slow, use str.startswith/endswith instead of slicing (or more generically don’t re-invent the wheel), boolean checks don’t need == True/False, be consistent in return statements (even if returning None, use return None, not just return).

    Interesting is the part on exceptions: two common mis-uses are putting too much in the try block, or catching exceptions that are too generic, so train yourself to use specific exceptions: ‘except SomeError’ instead of the catch-all ‘except’.

    Another interesting best practice is checking booleans, newcomers usually check False like ‘if len(somelist) == 0’, the Pythonic way is to just to use the fact that non-empty values are implicitly True, so in this case you could just do: ‘if not somelist’.

Tools to check for compliant PEP8

You can use pep8

Our digest.py seemed compliant but let’s make some edits to see this checker in action. I changed spaces from 4 to 2 in a method, mis-aligned a multi-line statement, and removed a whitespace before ‘=’. Of course pep8 complains:

$ pep8 digest.py
digest.py:24:3: E111 indentation is not a multiple of four
digest.py:25:3: E111 indentation is not a multiple of four
digest.py:26:3: E111 indentation is not a multiple of four
digest.py:50:18: E225 missing whitespace around operator
digest.py:54:80: E501 line too long (83 > 79 characters)

Another tool is flake8 which is “a wrapper around these tools: PyFlakes, pycodestyle and Ned Batchelder’s McCabe script”. It also has a nice integration in Vim: it runs the checks and presents them in a split window with line numbers, pretty convenient!

flake 8 inside vim

Btw I got this split window pressing ,f which I find easier on a Mac than F7, you can create a shortcut like this in your .vimrc:

autocmd FileType python map  ,f :call Flake8()

Another linter is pylint but I have not used that. What is your favorite linter?

pep8 meme

Wrapping it up

Always follow the PEP 8 style guide when writing Python code.

Therefor keep a copy of PEP8 at hand and review it often to ingrain its recommendations. It makes code cleaner and collaboration easier.

Using a linter tool is the best way to remind/ train yourself. Just google for plugins / integration with your favorite editor.

Any feedback, questions or experiences, use the comments below.

Update 25th of Oct 2017: there is actually a very nice stylized presentation of PEP8, created by Kenneth Reitz: http://pep8.org/


Keep Calm and Code in Python!

— Bob

Want a career as a Python Developer but not sure where to start?

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Increased emissions bmw ошибка
  • Hp m452 ошибка 59 f0