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

от автора

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

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

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

languages = [ 	"english", 	"russian", 	"italian" # Печалька. Такое иногда бывает. 	"spanish" ] 

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

languages = [ "english", "russian", "italianspanish" ] 

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

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

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

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

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

languages = [ 	"english", 	"russian", 	"italian", 	"spanish", # Если переместить этот элемент вверх, запятые не поломаются. ] 

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

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

languages = [ 	  "english" 	, "russian" 	, "italian" 	, "spanish" ] 

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

Новый способ

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

languages = [ 	("english"), 	("russian"), 	("italian") # Теперь потерянная запятая - синтаксичекая ошибка. 	("spanish") ] 

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

ссылка на оригинал статьи http://habrahabr.ru/company/radmin/blog/134080/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *