Есть ли способ узнать (во время кодирования), каких исключений ожидать при выполнении кода Python? В конце концов, я ловлю базовый класс исключений в 90% случаев, так как я не знаю, какой тип исключения может быть сгенерирован (и не говорю мне читать документацию. Много раз исключение может быть распространено из глубины. И многие раз документация не обновляется или не корректируется). Есть какой-нибудь инструмент, чтобы это проверить? (например, читая код Python и библиотеки)?
87
raise
строки, а не толькоBaseException
подклассы. Поэтому, если вы вызываете библиотечный код, который находится вне вашего контроля, этого дажеexcept Exception
недостаточно, поскольку он не перехватывает исключения строк. Как отмечали другие, здесь вы лаете не на то дерево.except Exception
отлично работает для перехвата исключений строк в Python 2.6 и новее.Ответы:
Думаю, решение могло быть неточным только из-за отсутствия правил статической типизации.
Мне неизвестен какой-то инструмент, который проверяет исключения, но вы могли бы придумать свой собственный инструмент, соответствующий вашим потребностям (хороший шанс немного поиграть со статическим анализом).
В качестве первой попытки вы могли бы написать функцию, которая строит AST, находит все
Raise
узлы, а затем пытается выяснить общие шаблоны создания исключений (например, вызов конструктора напрямую)Пусть
x
будет следующая программа:x = '''\ if f(x): raise IOError(errno.ENOENT, 'not found') else: e = g(x) raise e '''
Соберите AST с помощью
compiler
пакета:Затем определите
Raise
класс посетителя:class RaiseVisitor(object): def __init__(self): self.nodes = [] def visitRaise(self, n): self.nodes.append(n)
И пройдемся по собирающим
Raise
узлам AST :v = RaiseVisitor() compiler.walk(tree, v) >>> print v.nodes [ Raise( CallFunc( Name('IOError'), [Getattr(Name('errno'), 'ENOENT'), Const('not found')], None, None), None, None), Raise(Name('e'), None, None), ]
Вы можете продолжить, разрешая символы, используя таблицы символов компилятора, анализируя зависимости данных и т. Д. Или вы можете просто сделать вывод, что
CallFunc(Name('IOError'), ...)
«определенно должно означать повышениеIOError
», что вполне нормально для быстрых практических результатов :)источник
v.nodes
выше значение, вы не можете сказать, что это за штукаName('IOError')
илиName('e')
. Вы не знаете, на какое значение (значения) ониIOError
иe
могут указывать, поскольку это так называемые свободные переменные. Даже если их контекст привязки был известен (здесь вступают в игру таблицы символов), вы должны выполнить какой-то анализ зависимостей данных, чтобы вывести их точные значения (это должно быть сложно в Python).['IOError(errno.ENOENT, "not found")', 'e']
отображаемый пользователю, вполне подойдет. Но вы не можете сделать вывод о реальных классах значений переменных, представленных строками :) (извините за репост)exc_class = raw_input(); exec "raise " + exc_class
. Дело в том, что такой статический анализ на самом деле невозможен на динамическом языке, таком как Python.find /path/to/library -name '*.py' | grep 'raise '
получить аналогичные результаты :)Вам следует перехватывать только те исключения, которые вы будете обрабатывать.
Улавливать все исключения по их конкретным типам - нонсенс. Вы должны поймать определенные исключения, которые вы можете и будете обрабатывать. Для других исключений вы можете написать общий улов, который улавливает «базовое исключение», регистрирует его (используйте
str()
функцию) и завершает вашу программу (или делает что-то еще, что уместно в аварийной ситуации).Если вы действительно собираетесь обрабатывать все исключения и уверены, что ни одно из них не является фатальным (например, если вы запускаете код в какой-то изолированной среде), то ваш подход к отлову универсального BaseException соответствует вашим целям.
Вас также может заинтересовать справочник по языковым исключениям , а не справочник по используемой вами библиотеке.
Если ссылка на библиотеку действительно плохая и она не повторно генерирует собственные исключения при перехвате системных, единственный полезный подход - запускать тесты (возможно, добавить его в набор тестов, потому что если что-то недокументировано, это может измениться!) . Удалите файл, важный для вашего кода, и проверьте, какое исключение было выброшено. Введите слишком много данных и проверьте, какую ошибку они выдают.
В любом случае вам придется запускать тесты, поскольку, даже если бы метод получения исключений по исходному коду существовал, он не дал бы вам никакого представления, как вы должны справиться с любым из них . Возможно, вы должны показывать сообщение об ошибке «Файл needful.txt не найден!» когда поймаешь
IndexError
? Только тест может сказать.источник
Правильный инструмент для решения этой проблемы - unittests. Если у вас есть исключения, вызванные реальным кодом, которые не вызывают модульные тесты, вам нужно больше модульных тестов.
Учти это
def f(duck): try: duck.quack() except ??? could be anything
утка может быть любым предметом
Очевидно, у вас может быть кряк,
AttributeError
если у утки нет шарлатана, аTypeError
если у утки есть шарлатан, но его нельзя вызвать. Вы не представляете, чтоduck.quack()
может поднять, может быть, дажеDuckError
что-тоТеперь предположим, что у вас есть такой код
Если он вызывает,
IndexError
вы не знаете, пришло ли оно из arr [i] или из глубины функции базы данных. обычно не так важно, где произошло исключение, скорее, что-то пошло не так и то, что вы хотели, не произошло.Удобный метод - поймать и, возможно, повторно вызвать исключение, подобное этому
except Exception as e #inspect e, decide what to do raise
источник
Никто до сих пор не объяснил, почему у вас не может быть полного, 100% правильного списка исключений, поэтому я подумал, что стоит прокомментировать. Одна из причин - первоклассная функция. Допустим, у вас есть такая функция:
def apl(f,arg): return f(arg)
Теперь
apl
можно вызвать любое возникшее исключениеf
. Хотя в основной библиотеке не так много таких функций, это затрагивает все, что использует понимание списка с настраиваемыми фильтрами, отображение, сокращение и т. Д.Документация и анализаторы источников - единственные "серьезные" источники информации здесь. Просто имейте в виду, чего они не могут сделать.
источник
Я столкнулся с этим при использовании сокета, я хотел узнать все условия ошибки, в которых я бы столкнулся (поэтому вместо того, чтобы пытаться создавать ошибки и выяснять, какой сокет мне просто нужен краткий список). В конце концов, я ввел grep'ing "/usr/lib64/python2.4/test/test_socket.py" для "поднять":
$ grep raise test_socket.py Any exceptions raised by the clients during their tests raise TypeError, "test_func must be a callable function" raise NotImplementedError, "clientSetUp must be implemented." def raise_error(*args, **kwargs): raise socket.error def raise_herror(*args, **kwargs): raise socket.herror def raise_gaierror(*args, **kwargs): raise socket.gaierror self.failUnlessRaises(socket.error, raise_error, self.failUnlessRaises(socket.error, raise_herror, self.failUnlessRaises(socket.error, raise_gaierror, raise socket.error # Check that setting it to an invalid value raises ValueError # Check that setting it to an invalid type raises TypeError def raise_timeout(*args, **kwargs): self.failUnlessRaises(socket.timeout, raise_timeout, def raise_timeout(*args, **kwargs): self.failUnlessRaises(socket.timeout, raise_timeout,
Это довольно краткий список ошибок. Конечно, это работает только от случая к случаю и зависит от точности тестов (как правило, так и есть). В противном случае вам нужно практически перехватить все исключения, зарегистрировать их, проанализировать их и выяснить, как с ними обращаться (что с модульным тестированием было бы несложно).
источник
Есть два способа, которые я нашел информативными. Во-первых, запустите код в iPython, который отобразит тип исключения.
n = 2 str = 'me ' str + 2 TypeError: unsupported operand type(s) for +: 'int' and 'str'
Во втором случае мы довольствуемся слишком большим уловом и со временем улучшаем его. Включите
try
выражение в свой код и поймитеexcept Exception as err
. Выведите достаточно данных, чтобы узнать, какое исключение было сгенерировано. По мере появления исключений улучшайте свой код, добавляя более точноеexcept
предложение. Когда вы почувствуете, что перехватили все соответствующие исключения, удалите все включенное. В любом случае это хорошо, потому что это проглатывает ошибки программирования.try: so something except Exception as err: print "Some message" print err.__class__ print err exit(1)
источник
Обычно вам нужно перехватить исключение только в нескольких строках кода. Вы бы не хотели помещать
main
вtry except
предложение всю свою функцию . для каждых нескольких строк вы всегда должны (или иметь возможность легко проверить), какое исключение может возникнуть.в документации есть исчерпывающий список встроенных исключений . не пытайтесь исключить те исключения, которых вы не ожидаете, они могут быть обработаны / ожидаемы в вызывающем коде.
edit : то, что может быть выброшено, очевидно, зависит от того, что вы делаете! доступ к случайному элементу последовательности:,
IndexError
случайному элементу dict:KeyError
и т. д.Просто попробуйте запустить эти несколько строк в IDLE и вызвать исключение. Но, естественно, unittest было бы лучшим решением.
источник