Я часто попадаю на позиции в моем коде, где я снова и снова проверяю определенное условие.
Я хочу привести небольшой пример: предположим, что есть текстовый файл, который содержит строки, начинающиеся с «a», строки, начинающиеся с «b», и другие строки, и я на самом деле хочу работать только с первыми двумя видами строк. Мой код будет выглядеть примерно так (используя python, но читайте его как псевдокод):
# ...
clear_lines() # removes every other line than those starting with "a" or "b"
for line in lines:
if (line.startsWith("a")):
# do stuff
elif (line.startsWith("b")):
# magic
else:
# this else is redundant, I already made sure there is no else-case
# by using clear_lines()
# ...
Вы можете себе представить, что я проверю не только это условие, но и другие функции и так далее.
Вы думаете об этом как о шуме или это добавляет ценность моему коду?
coding-style
clean-code
marktani
источник
источник
assert()
туда, чтобы помочь с тестированием, но помимо этого, вероятно, чрезмерно. Тем не менее, это будет меняться в зависимости от ситуации.elif (line.startsWith("b"))
? кстати, вы можете смело убирать те окружающие скобки на условиях, они не идиоматичны в Python.Ответы:
Это чрезвычайно распространенная практика, и способ борьбы с ней заключается в использовании фильтров более высокого порядка .
По сути, вы передаете функцию методу filter вместе со списком / последовательностью, по которой вы хотите фильтровать, и результирующий список / последовательность содержит только те элементы, которые вы хотите.
Я не знаком с синтаксисом Python (хотя он содержит такую функцию, как видно по ссылке выше), но в c # / f # это выглядит так:
C #:
f # (предполагается, что ienumerable, иначе будет использован List.filter):
Итак, чтобы быть ясно: если вы используете проверенный и проверенный код / шаблоны, это плохой стиль. Это и изменение списка в памяти так, как вы это делаете через clear_lines (), лишает вас безопасности потоков и любых надежд на параллелизм, которые вы могли бы иметь.
источник
(line for line in lines if line.startswith("a") or line.startswith("b"))
.clear_lines
действительно плохая идея. В Python вы, вероятно, будете использовать генераторы, чтобы избежать загрузки всего файла в память.lines
это сгенерированная коллекция.skip
,take
,reduce
(aggregate
в .NET),map
(select
в .NET), и есть больше , но это действительно твердое начало.Недавно мне пришлось реализовать программатор прошивки, используя формат S-записи Motorola , очень похожий на то, что вы описываете. Поскольку у нас было некоторое время, мой первый черновик игнорировал избыточность и делал упрощения на основе подмножества, которое мне фактически нужно было использовать в моем приложении. Он легко прошел мои тесты, но потерпел неудачу, как только кто-то попробовал. Понятия не было, в чем проблема. Он прошел весь путь, но потерпел неудачу в конце.
Поэтому у меня не было выбора, кроме как реализовать все избыточные проверки, чтобы сузить суть проблемы. После этого мне потребовалось около двух секунд, чтобы найти проблему.
Мне потребовалось около двух часов, чтобы сделать это правильно, но я потратил впустую день других людей на устранение неисправностей. Очень редко, если несколько циклов процессора стоят дня, потраченного впустую на устранение неисправностей.
Тем не менее, когда речь идет о чтении файлов, часто бывает полезно спроектировать ваше программное обеспечение так, чтобы оно читало и обрабатывало по одной строке за раз, а не считывало весь файл в память и обрабатывало его в памяти. Таким образом, он все равно будет работать с очень большими файлами.
источник
Вы можете поднять исключение в
else
случае. Таким образом, это не избыточно. Исключение составляют вещи, которые не должны происходить, но в любом случае проверяются.источник
"c"
, это может быть менее понятно.При проектировании по контракту каждый предполагает, что каждая функция должна выполнять свою работу, как описано в ее документации. Таким образом, каждая функция имеет список предварительных условий, то есть условий на входах функции, а также постусловий, то есть условий на выходе функции.
Функция должна гарантировать своим клиентам, что, если входные данные соответствуют предварительным условиям, выходной результат будет соответствовать описанным постусловиям. Если хотя бы одно из предварительных условий не соблюдается, функция может делать то, что она хочет (сбой, вернуть любой результат, ...). Поэтому предварительные и постусловия представляют собой семантическое описание функции.
Благодаря контракту, функция уверена, что ее клиенты используют ее правильно, а клиент уверен, что функция выполняет свою работу правильно.
Некоторые языки обрабатывают контракты изначально или через специальную среду. Для остальных лучше всего проверить предварительные и постусловия благодаря утверждениям, как сказал @Lattyware. Но я бы не стал называть это защитным программированием, поскольку, на мой взгляд, эта концепция больше ориентирована на защиту от действий пользователя.
Если вы используете контракты, вы можете избежать избыточно проверенного условия, так как либо вызываемая функция отлично работает, и вам не нужна двойная проверка, либо вызываемая функция не функционирует, и вызывающая функция может вести себя так, как она хочет.
Сложнее всего определить, какая функция за что отвечает, и строго задокументировать эти роли.
источник
На самом деле вам не нужен clear_lines () в начале. Если строка не является ни «a», ни «b», условия просто не сработают. Если вы хотите избавиться от этих строк, превратите остальное в clear_line (). В его нынешнем виде вы делаете два прохода через ваш документ. Если вы пропустите clear_lines () в начале и сделаете это как часть цикла foreach, тогда вы сократите время обработки вдвое.
Это не только плохой стиль, это плохо в вычислительном отношении.
источник
"a"
/"b"
. Не сказать, что это вероятно ( ясное имя подразумевает, что их отбрасывают), просто есть вероятность, что это необходимо. Если этот набор строк будет многократно повторяться в будущем, может быть целесообразно удалить их заранее, чтобы избежать бессмысленной итерации.Если вы действительно хотите что-то сделать, если найдете недопустимую строку (например, выходной текст отладки), я бы сказал, что это совершенно нормально. Несколько дополнительных строк и несколько месяцев спустя, когда он перестает работать по неизвестной причине, вы можете посмотреть на вывод, чтобы узнать почему.
Однако, если это можно просто игнорировать, или вы точно знаете, что никогда не получите неверную строку, тогда дополнительная ветвь не нужна.
Лично я всегда добавляю по крайней мере вывод трассировки для любого непредвиденного состояния - это делает жизнь намного проще, когда у вас есть ошибка с прикрепленным выводом, сообщающая вам точно, что пошло не так.
источник
Я ненавижу
if...then...else
конструкции. Я бы избежал всей проблемы:источник