Давайте взглянем на эту дискуссию с другой точки зрения и выберем, какая из них лучше.

Ладно, это громкое название. Этот спор похож на пожизненную войну для программистов (немного преувеличение 😁). Некоторые люди предпочитают использовать Посмотрите, прежде чем прыгнуть (LBYL), другие считают, что лучше Проще попросить прощения, чем разрешения (EAFP). Затем часть из нас думает: «Ну, это зависит от обстоятельств».

В этой статье мы поговорим о том, действительно ли нам нужно выбирать между этими двумя или лучше использовать оба, в зависимости от деталей реализации? Лучше ли кодировать идиоматически, чем строго придерживаться предпочитаемой нами догмы? В любом случае, в качестве дополнения я приведу несколько примеров на Python, Go и JavaScript.

Введение

Прежде чем перейти непосредственно к примерам кода, давайте кратко опишем эти два подхода.

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

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

Как и в Look Before You Leap, вы в первую очередь ограничиваете возникновение этой ошибки, сокращая поток выполнения. Но в Легче попросить прощения, чем разрешения вы позволяете этой ошибке произойти, а затем, если есть ошибка, вы с ней справитесь.

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

Питон

В Python, если вы хотите использовать LBYL, у вас будет код, похожий на этот.

В этом коде нам нужно проверить, есть ли в словаре ключи для имени и цены. Если нет, то код запускает оператор else.

Теперь сравните его с подходом EAFP. Как вы думаете, какой из них лучше?

Если вы удалите пару ключ-значение цены, запустится оператор exclude. Если ошибки нет, то оператор try будет работать как обычно.

В целом, сообщество Python предпочитает Легче попросить прощения, чем разрешения. Потому что, допустим, в вашем коде много условий, которые могут пойти не так. Если вы используете Look Before You Leap, у вас будет много операторов if-else для проверки пограничных случаев. Помните, что набор операторов if-else сделает ваш код относительно медленнее по сравнению с обработкой try-except, но выполнение обработки исключений будет стоить вам дороже по сравнению с одним оператором if-else (вы можете сравнить их, используя timeit). Помимо производительности, EAFP имеет гораздо более приятный синтаксис. Особенно, если вы хотите уменьшить сложность кода.

Хорошо, но когда я должен выбрать EAFP и когда LBYL?

В большинстве случаев следует использовать EAFP. Это идиоматический способ обработки ошибок в Python. Но если вы считаете, что в вашем коде не будет слишком много пограничных случаев и он будет проще с LBYL, это хороший знак для его использования. Помните, что обработка исключений стоит дорого, поэтому, если в вашем коде есть шанс выдать много исключений, лучше использовать LBYL.

Означает ли это, что я буду часто использовать EAFP в Python? Да, более вероятно. Поэтому важно понимать, как правильно его использовать. Ключевая идея, которую следует помнить, заключается в том, чтобы не использовать общую обработку исключений, а быть конкретной.

В приведенном выше примере исключение возникает, когда мы пытаемся получить доступ к неуказанному ключу в словаре. Таким образом, вместо использования Exception (или даже BaseException) вместо этого вы должны указать KeyError в операторе exclude.

Go

В отличие от Python, идиоматическим способом обработки ошибок в Go является Посмотрите, прежде чем прыгать. На самом деле в Go нет ни try-except, ни try-catch. У вас просто есть старый оператор if-else.

Да, у нас, скорее всего, будет длинный и многословный код, но действительно ли это недостаток Go? Не совсем так Go был разработан. Как я уже упоминал в предыдущем разделе, обработка исключений стоит дорого. Если нам нужно обработать много исключений, наш код будет относительно медленнее. Кроме того, разработчики Go предпочитают явную обработку ошибок.

Взгляните на этот пример:

Обычно функции в Go возвращают пару/кортеж; первое - результат, второе - ошибка. В случае ошибки поток выполнения останавливается и возвращается к вызывающей стороне. Если ошибки нет, поток продолжается.

Но есть ли способ написать EAFP на Go? Ну можно (вроде). Питер Верхас может дать вам хороший фрагмент для этого!

Даже если вы можете написать EAFP на Go, это не значит, что вы должны использовать его неразумно. В общем, вы должны придерживаться LBYL, потому что это идиоматический способ. Если только у вас есть какой-то очень специфический случай, требующий такого подхода, вы можете его использовать. Но все же, помните о своем решении.

Еще одно замечание: хотя в большинстве случаев вы будете использовать LBYL, как и в Python, вам нужно знать, как правильно его использовать (я также предоставляю дополнительные ресурсы, если вы хотите узнать о лучших методах обработки ошибок в разделе ресурсов). В го есть известный термин Счастливый путь. Структура будет такой: у вас есть вызов функции, который возвращает значение и ошибку. На одну строку ниже вызова функции у вас есть обработка ошибок, и вам нужно корректно обрабатывать эту ошибку, а не просто проверять, есть ли ошибка. Кроме того, вам всегда нужно сначала обработать ошибку. Пусть за ним следует счастливый сценарий, если нет ошибки.

Если вы внимательно присмотритесь, он имеет паттерн исполнения сверху вниз. Между управляющими структурами нет прыжков. Именно это делает код Go многословным и явным.

JavaScript

Как и Python, вы можете использовать EAFP и LBYL в JavaScript. Но главное отличие в том, что вы не можете указать, какой тип ошибки возникает внутри блока try-catch. Вы можете иметь KeyError, ValueError, Exception и т. д. в Python, но у вас есть общая ошибка в JavaScript. Это означает, что вам нужно комбинировать EAFP и LBYL, чтобы добиться того же поведения, что и в Python.

Давайте рассмотрим пример.

Из приведенного выше кода мы используем Axios в качестве HTTP-клиента. В этом случае, если localhost:3000 возвращает HTTP-статус not ok (HTTP-код 3xx, 4xx или 5xx), запускается обработка исключений. Но если вы хотите такое же поведение, как в Python, вы должны использовать операторы if-else для конкретной обработки исключений.

Зная это и имея предыдущие знания о том, что нам нужно специально обрабатывать исключения, в большинстве случаев вам потребуется объединить EAFP и LBYL. Это правда, что JavaScript хорошо известен как гибкий язык. Но, по моему личному мнению, я не рекомендую использовать общую обработку исключений. Хотя он прост в использовании, он не совсем надежен.

Заключение

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

Помимо этого, мы должны придерживаться идиоматичности, когда пишем код. Почему? Я почти уверен, что если мы изучаем язык, мы пытаемся звучать как его носители. Мы будем изучать не только язык, но и их культуру. Чтобы лучше понять этот язык, мы должны думать как местные жители.

Что вы думаете?

Спасибо за чтение и счастливого кодирования!

Ресурсы