Каков принцип EAFP в Python?

Ответы:

216

Из глоссария :

Проще просить прощения, чем разрешения. Этот общий стиль кодирования Python предполагает наличие допустимых ключей или атрибутов и перехватывает исключения, если предположение оказывается ложным. Это чистый и быстрый стиль характеризуется наличием многих tryи exceptзаявлений. Техника контрастирует со стилем LBYL, общим для многих других языков, таких как C.

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

ЭСПЦ:

try:
    x = my_dict["key"]
except KeyError:
    # handle missing key

LBYL:

if "key" in my_dict:
    x = my_dict["key"]
else:
    # handle missing key

Версия LBYL должна дважды искать ключ в словаре, и ее также можно считать немного менее читаемой.

Свен Марнах
источник
34
Улучшение будет заключаться в том, что другим преимуществом является избегание условий гонки ... например, просто попробуйте открыть файл, и если вы его получите, вы его получите. Вместо того, чтобы посмотреть , сможете ли вы получить его , затем попытаться получить его позже и понять, что за минимальное количество времени между проверкой и попыткой доступа вы можете получить его дольше.
Джон Клементс
23
Python также предоставляет способ избежать обоих из них, если обработчик просто присваивает значение по умолчанию x когда ключ не существует: x = mydict.get('key')вернет, Noneесли 'key'не в my_dict; Вы также можете это сделать .get('key', <something>), и тогда x будет назначен что-то, если ключ отсутствует в словаре. dict.setdefault()и collections.defaultdictхорошие вещи для того, чтобы избежать лишнего кода.
JAB
1
Я думаю except KeyErrorтакже, как AttributeErrorпростые, но некоторые из худших примеров. Очень много раз я застревал, отлаживая что-то, потому что он except AttributeErrorбыл помещен в неправильное место, что в итоге перехватывало неверную атрибутивную ошибку, возникшую глубже в цепочке. Лучшие примеры , которые я думаю , являются: try: open() ... except: IOError. Илиtry: parseLine() ... except ParseError
Ски
4
@ski Это немного другая проблема. Вы должны всегда держать блок try как можно меньше, чтобы избежать перехвата неправильного исключения. Также обратите внимание, что я обычно не предпочитаю стиль EAFP. Я просто отвечаю на вопрос здесь и заявляю, что некоторые люди предпочитают это. Я в каждом конкретном случае определяю, какой код выглядит для меня наиболее читабельным.
Свен Марнач
1
Я думал, что стоит упомянуть, что Грейс Хоппер , вероятно, является источником этой фразы, с ее цитатой: «Дерзай и делай. Проще просить прощения, чем получать разрешение» (не ограничиваясь программированием).
Фабьен Сноваверт
9

Я попытаюсь объяснить это другим примером.

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

LBYL - Смотри, прежде чем прыгать

Возможно, мы захотим проверить, можем ли мы получить доступ к файлу, и если мы сможем, мы откроем его и распечатаем содержимое. Если мы не можем получить доступ к файлу, мы попадем на elseчасть. Причина, по которой это условие гонки, заключается в том, что мы сначала проводим проверку доступа. К тому времени, когда мы достигаем, with open(my_file) as f:возможно, мы больше не можем получить к нему доступ из-за некоторых проблем с разрешениями (например, другой процесс получает эксклюзивную блокировку файла). Этот код, скорее всего, выдаст ошибку, и мы не сможем ее отследить, потому что думали, что можем получить доступ к файлу.

import os

my_file = "/path/to/my/file.txt"

# Race condition
if os.access(my_file, os.R_OK):
    with open(my_file) as f:
        print(f.read())
else:
    print("File can't be accessed")

EAFP - проще просить прощения, чем разрешения:

В этом примере мы просто пытаемся открыть файл, и если мы не можем открыть его, он выдаст IOError. Если мы сможем, мы откроем файл и распечатаем его содержимое. Таким образом, вместо того, чтобы спросить что-то, мы пытаемся это сделать. Если это работает, отлично! Если это не так, мы ловим ошибку и обрабатываем ее.

# # No race condition
try:
    f = open(my_file)
except IOError as e:
    print("File can't be accessed")
else:
    with f:
        print(f.read())
Апурв Патне
источник
Я не уверен, что правильно описывать это как состояние гонки. Либо файл доступен, либо нет.
ds4940
3
@ ds4940 Состояние гонки, если доступность файла изменяется между строками 6 и 7, то есть между проверкой доступности файла и его открытием.
Маркус фон
@MarkusvonBroady согласился, отредактировал ответ, чтобы привести пример другого участника в состоянии гонки.
ds4940
6

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

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

инженер
источник