2009-02-28 7 views
26

Я прочитал в более раннем answer, что обработка исключений является дешевой в Python, поэтому мы не должны делать предварительную проверку.Незначительная обработка исключений в Python?

Я еще не слышал об этом раньше, но я относительно новичок в Python. Обработка исключений означает динамический вызов и статический возврат, тогда как оператор if является статическим вызовом, статическим возвратом.

Как сделать проверку плохой и try-except быть хорошим, кажется, наоборот. Может кто-то объяснить это мне?

+2

Связанная дискуссия: http://stackoverflow.com/questions/204308/checking-for-member-existence-in-python – tzot

+7

+1 Для опроса Евангелия вместо того, чтобы верить всему, что вы читаете :) –

ответ

24

Вы можете найти это сообщение полезным: Try/Except Performance in Python: A Simple Test, где Патрик Альтман сделал несколько простых тестов, чтобы увидеть, что производительность в различных сценариях предустановлена ​​(в частности, для ключей словаря в данном случае) и использует только исключения. Код также предоставляется, если вы хотите приспособить его для проверки других условностей.

Выводы он пришел:

Из этих результатов, я думаю, что это справедливо быстро определить ряд выводов:

  1. Если существует высокая вероятность того, что элемент не существует, то вам лучше проверить его с has_key.
  2. Если вы не собираетесь делать что-либо за исключением, если он воскресают, то вам лучше не положить один уже кроме
  3. Если есть вероятность, что элемент существует, то существует очень небольшое преимущество использования блока try/except вместо использования has_key, Однако преимущество очень незначительное.
+3

has_key не такой хорошая идея. AFAIK, (somekey in dict)/dict.get лучше. – batbrat

+3

Я бы посоветовал не помещать исключение, которое вы хотите поймать за исключением: потому что тогда вы не заметите, что какие-либо другие исключения возникают, а отладка сложнее. Но исключения ИМХО следует использовать редко в любом случае. Если вы можете использовать тест. – MrTopf

+1

Я согласен с обоими комментариями выше. В качестве дополнительной точки данных я просто добавил случаи, используя 'if 'key' в d', а не' if d.has_key ('key') 'к эталонному скрипту, связанному выше, и я считаю, что это самый быстрый подход - он становится быстрее, чем исключения, даже в том случае, когда ключ существует в словаре. Конечно, этот тест не очень научный, но это интересно. Я использовал 2.7.3 на x86_64. – Cartroo

4

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

Обратите внимание, что проверка с помощью if-elif-else должна оценивать условие каждый раз. Обработка исключений, в том числе поиск обработчика исключений, происходит только в исключительном состоянии, которое, вероятно, будет редко встречаться в большинстве случаев. Это явное повышение эффективности. Как отметил Джей, лучше использовать условную логику, а не исключения, когда существует высокая вероятность отсутствия ключа. Это происходит потому, что, если ключ отсутствует в большинстве случаев, это не исключительное условие.

Тем не менее, я предлагаю вам не беспокоиться об эффективности и, скорее, о значении. Используйте обработку исключений для обнаружения исключительных случаев и проверки условий, когда вы хотите что-то решить. Мне вчера напомнили о важности значения С.Лотта.

пример:

def xyz(key): 
    dictOb = {x:1, y:2, z:3} 
    #Condition evaluated every time 
    if dictOb.has_key(key): #Access 1 to dict 
     print dictOb[key] #Access 2 

Versus

#Exception mechanism is in play only when the key isn't found. 
def xyz(key): 
    dictOb = {x:1, y:2, z:3} 
    try: 
     print dictOb[key] #Access 1 
    except KeyError: 
     print "Not Found" 

В целом, имея некоторый код, который обрабатывает что-то, как отсутствующий ключ, только в случае нуждается обработки исключений, но в ситуации, когда ключ больше не присутствует, то, что вы действительно хотите сделать, - это решить, присутствует ли ключ => if-else. Python подчеркивает и поощряет говорить, что вы имеете в виду.

Почему исключения предпочтительнее, если-Элиф ->

  1. Он выражает смысл более четко, когда вы смотрите Foe исключительный ака необычных/неожиданных условий в вашем коде.
  2. Это более чистый и более читаемый.
  3. Это более гибкий.
  4. Его можно использовать для написания более сжатого кода.
  5. Избегает множества неприятных проверок.
  6. Это более удобно.

Примечание Когда мы избегаем использования примерочных, за исключением, Исключения продолжают воспитываются. Исключения, которые не обрабатываются, просто переходят к обработчику по умолчанию. Когда вы используете try-except, вы можете самостоятельно обработать эту ошибку. Это может быть более эффективным, поскольку if-else требует оценки условий, в то время как поиск обработчика исключений может быть более дешевым. Даже если это правда, выигрыш от него будет слишком незначительным, чтобы думать о нем.

Надеюсь, мой ответ поможет.

+2

Я нахожу, что если версия более читаема, на самом деле, особенно если вы используете новый синтаксис «if key in dictOb». И здесь KeyError, по крайней мере, довольно очевиден; иногда гораздо сложнее сказать, что означает исключение, без необходимости искать его, тогда как if обычно является явным. – DNS

+0

Ну, в этом маленьком примере это не помогает читаемости. Я просто пытаюсь проиллюстрировать свою точку зрения. С другой стороны, когда у вас есть ряд исключительных условий, он становится беспорядочным, если вы используете if-else. Из личного опыта я знаю, что это плохая идея. – batbrat

+1

* Плохая идея использовать if-else. Учиться читать исключения не так уж сложно. Это проще, чем поддерживать беспорядочный if-else. – batbrat

1

Что такое статические или динамические вызовы и возвращаемые данные, и почему вы считаете, что вызовы и обратные вызовы на Python различны в зависимости от того, выполняете ли вы это в блоке try/except? Даже если вы не ловите исключения, Python по-прежнему должен обрабатывать вызов, возможно, что-то поднимая, поэтому для Python это не имеет никакого значения в отношении того, как обрабатываются вызовы и возвращает.

Каждый вызов функции в Python включает в себя толкание аргументов в стек и вызов вызываемого. Каждое завершение функции сопровождается вызывающим абонентом во внутренней проводке Python, проверяя успешное завершение или исключение и обрабатывает его соответствующим образом. Другими словами, если вы считаете, что есть некоторая дополнительная обработка, когда вы находитесь в блоке try/except, который каким-то образом пропускается, когда вы не в одном, вы ошибаетесь. Я предполагаю, что это то, чем вы «статичным» и «динамическим» различием.

Кроме того, это вопрос стиля, и опытные разработчики Python приходят к тому, чтобы хорошо разбираться в исключении, так что, когда они видят соответствующий try/except вокруг вызова, он более читабельен, чем условная проверка.

8

С Python, легко проверить различные возможности для скорости - получить знать timeit module:

... Пример сеанса (с помощью командной строки), которые сравнивают стоимость использования hasattr() против ,попробуйте/за исключением проверки отсутствующих и существующих атрибутов объекта.

% timeit.py 'try:' ' str.__nonzero__' 'except AttributeError:' ' pass' 
100000 loops, best of 3: 15.7 usec per loop 
% timeit.py 'if hasattr(str, "__nonzero__"): pass' 
100000 loops, best of 3: 4.26 usec per loop 
% timeit.py 'try:' ' int.__nonzero__' 'except AttributeError:' ' pass' 
1000000 loops, best of 3: 1.43 usec per loop 
% timeit.py 'if hasattr(int, "__nonzero__"): pass' 
100000 loops, best of 3: 2.23 usec per loop 

Эти временные результаты показывают в hasattr() случае, поднимая исключение медленно, но выполняет тест медленнее, чем не поднимая исключение. Таким образом, с точки зрения времени работы, использование исключения для обработки исключительных случаев имеет смысл.

EDIT: параметр командной строки -n по умолчанию будет достаточно большим, чтобы время выполнения имело смысл. quote from the manual:

Если -n не задан, подходящее число петель рассчитывается не пытается последовательные полномочия 10 до полного времени составляет по меньшей мере 0,2 секунды.

+0

Просто интересно, есть ли причина в 10 раз больше попыток для третьего теста? –

+0

Добавлена ​​еще одна цитата из руководства - 3-й тест был слишком быстрым для 100000 циклов. – gimel

35

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

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

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

+7

Я не согласен. Python достаточно быстр. То же самое с C и сборкой. Вы внедряете C в Python в узкие места, так же, как вы встраиваете сборку в C по узким местам. – batbrat

+16

Как ни странно, я согласен со всем, что вы сказали после «Я не согласен». :) –

+2

Я думаю, ему не нравится, когда Python называют «[медленным] языком сценариев». – Phob

9

«Может кто-нибудь объяснить это мне?»

Зависит.

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

«Обработка исключений - это динамический вызов и статический возврат, тогда как оператор if является статическим вызовом, статическим возвратом».

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

Возможно, этот «динамический вызов» не является самой дорогостоящей частью операции. Возможно, оценка выражения if-выражения немного дороже, чем простое «try-it-and-fail».

Оказывается, что внутренние проверки целостности Python почти такие же, как и ваш if-statement, и их необходимо выполнить в любом случае. Поскольку Python всегда будет проверять, ваш if-statement (в основном) избыточен.

Вы можете прочитать о обработке исключений низкого уровня в http://docs.python.org/c-api/intro.html#exceptions.


Редактировать

Больше к точке: КРП против, кроме дебатов не имеет значения.

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

Использовать код Очистить и Значение. Не тратьте время на такие микро-оптимизации.

+3

Эта дискуссия не имеет значения только после того, как вы поймете, что это не имеет значения. Я имею в виду, что только с тех пор, как мы знаем, что разница в производительности пренебрежимо мала, мы можем спокойно оставить ее и сосредоточиться на самом коде. Если обработка исключений была медленнее обычного «if» на порядок, мы не смогли бы сказать, что это не имеет значения. Абстракции утечки. Мы не должны беспокоиться о них большую часть времени, но мы не можем игнорировать потенциальную опасность, слепо игнорируя проблемы с производительностью. – Michael

+0

+1 для справки – Wolf

22

Отложив в сторону измерения производительности, которые другие говорили, руководящий принцип часто структурирован как «легче просить прощения, чем спросить разрешения» и «смотреть, прежде чем прыгать».

Рассмотрим эти два фрагмента:

# Look before you leap 
if not os.path.exists(filename): 
    raise SomeError("Cannot open configuration file") 
f = open(filename) 

против

# Ask forgiveness ... 
try: 
    f = open(filename) 
except IOError: 
    raise SomeError("Cannot open configuration file") 

Эквивалент? На самом деле, нет. ОС - многозадачные системы. Что произойдет, если файл был удален между тестом для вызова «существует» и «открытым»?

Что произойдет, если файл существует, но он не читается? Что, если это имя каталога вместо файла. Могут быть много возможных режимов отказа, и проверка их всех - это большая работа. Тем более, что «открытый» звонок уже проверяет и сообщает обо всех возможных ошибках.

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

1

Общее сообщение, как сказал С.Лотт, заключается в том, что попытка/исключение не причиняет вреда, поэтому вы должны свободно использовать его, когда это кажется уместным.

Эта дискуссия часто называется «LBYL vs. EAFP» - это «смотреть, прежде чем прыгать», «проще просить прощения, чем разрешения». Alex Martelli весит на эту тему: http://mail.python.org/pipermail/python-list/2003-May/205182.html Этим дебатам почти шесть лет, но я не думаю, что основные проблемы сильно изменились.

Смежные вопросы