Подтвердить что ты не робот

Python: как я могу узнать, какие исключения могут быть выбраны из вызова метода?

Есть ли способ узнать (во время кодирования), какие исключения ожидать при выполнении кода python? Я в конечном итоге поймаю базовый класс Exception 90% времени, так как я не знаю, какой тип исключения может быть выброшен (и не говорите мне, чтобы я читал документацию. Много раз исключение можно распространять из глубины. раз документация не обновляется или не корректируется). Есть ли какой-нибудь инструмент для проверки этого? (например, прочитав код python и libs)?

4b9b3361

Ответ 1

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

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

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

Пусть x - следующая программа:

x = '''\
if f(x):
    raise IOError(errno.ENOENT, 'not found')
else:
    e = g(x)
    raise e
'''

Создайте AST с помощью пакета compiler:

tree = compiler.parse(x)

Затем определите класс Raise:

class RaiseVisitor(object):
    def __init__(self):
        self.nodes = []
    def visitRaise(self, n):
        self.nodes.append(n)

И пройдите узлы сборки Raise:

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", что вполне нормально для быстрых практических результатов:)

Ответ 2

Вы должны обрабатывать исключения, которые вы будете обрабатывать.

Захват всех исключений по их конкретным типам - это вздор. Вы должны поймать определенные исключения, которые вы можете и будете обрабатывать. Для других исключений вы можете написать общий catch, который ловит "базовое исключение", регистрирует его (используйте функцию str()) и завершает работу вашей программы (или делает что-то еще, что подходит в аварийной ситуации).

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

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

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

В любом случае вам придется запускать тесты, так как даже , если существует метод получения исключений по исходному коду, это не даст вам представления о том, как вы должны обращаться с любым из этих. Возможно, вы должны показывать сообщение об ошибке "Файл needful.txt не найден!" когда вы ловите IndexError? Только тест может сказать.

Ответ 3

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

Рассмотрим это

def f(duck):
    try:
        duck.quack()
    except ??? could be anything

duck может быть любым объектом

Очевидно, что у вас может быть AttributeError, если утка не имеет шарлатана, TypeError, если утка имеет шарлатан, но она не может быть вызвана. Вы не представляете, что может поднять duck.quack(), возможно, даже DuckError или что-то

Теперь предположим, что у вас есть такой код

arr[i] = get_something_from_database()

Если он вызывает IndexError, вы не знаете, пришел ли он из arr [i] или из глубины функции базы данных. обычно это не имеет большого значения, где произошло исключение, а что-то пошло не так, а то, что вы хотели, не произошло.

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

except Exception as e
    #inspect e, decide what to do
    raise

Ответ 4

Пока никто не объяснил, почему у вас нет полного, 100% правильного списка исключений, поэтому я подумал, что стоит комментировать. Одной из причин является первоклассная функция. Скажем, что у вас есть такая функция:

def apl(f,arg):
   return f(arg)

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

Документация и исходные анализаторы являются единственными "серьезными" источниками информации здесь. Просто имейте в виду, что они не могут сделать.

Ответ 5

Я столкнулся с этим при использовании сокета, я хотел узнать все ошибки, в которые я мог бы работать (вместо того, чтобы пытаться создавать ошибки и выяснить, какой сокет мне нужен только для краткого списка). В конечном итоге я закончил 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,

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

Ответ 6

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

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

edit: то, что может быть выбрано, зависит, очевидно, от того, что вы делаете! доступ к случайному элементу последовательности: IndexError, случайный элемент dict: KeyError и т.д.

Просто попробуйте запустить эти несколько строк в IDLE и вызвать исключение. Но unittest было бы лучшим решением, естественно.

Ответ 7

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

n = 2
str = 'me '
str + 2
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Во втором случае мы соглашаемся на слишком много ловить и улучшать его. Включите выражение try в свой код и поймайте , кроме Exception, как err. Распечатайте достаточные данные, чтобы узнать, какое исключение было выбрано. По мере исключения исключений улучшите свой код, добавив более точное исключение. Когда вы чувствуете, что кэшировали все соответствующие исключения, удалите все включено. В любом случае хорошо, потому что он проглатывает ошибки программирования.

try:
   so something
except Exception as err:
   print "Some message"
   print err.__class__
   print err
   exit(1)