Предупреждения с точки зрения вызывающего абонента (он же Python-эквивалент карпа Perl)?

Краткая версия:

Есть ли способ добиться в Python того же эффекта, что и Perl Carp :: carp Утилита ?

Длинная версия (для тех, кто не знаком с Carp :: carp ):

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

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

К сожалению, это не то, что происходит, по крайней мере, по умолчанию, при использовании Python. Вместо этого последняя строка трассировки будет относиться к чему-то внутри кода библиотеки, где на самом деле исключение было raise 'd, что было бы весьма непонятно для предполагаемой аудитории this конкретная трассировка.

Пример:

# spam.py (library code)
def spam(ham, eggs):
    '''
    Do something stupid with ham and eggs.

    At least one of ham and eggs must be True.
    '''
    _validate_spam_args(ham, eggs)
    return ham == eggs

def _validate_spam_args(ham, eggs):
    if not (ham or eggs):
        raise ValueError('if we had ham '
                         'we could have ham and eggs '
                         '(if we had eggs)')



# client.py (client code)
from spam import spam

x = spam(False, False)

Когда мы запускаем client.py , мы получаем:

% python client.py
Traceback (most recent call last):
  File "client.py", line 3, in 
    x = spam(False, False)
  File "/home/jones/spam.py", line 7, in spam
    _validate_spam_args(ham, eggs)
  File "/home/jones/spam.py", line 12, in _validate_spam_args
    raise ValueError('if we had ham '
ValueError: if we had ham we could have ham and eggs (if we had eggs)

, тогда как то, что нам нужно, будет ближе к:

% python client.py
Traceback (most recent call last):
  File "client.py", line 3, in 
    x = spam(False, False)
ValueError: if we had ham we could have ham and eggs (if we had eggs)

... с ошибочным кодом ( x = spam (False, False) ) в качестве последней строки трассировки.

Что нам нужно, так это способ сообщить об ошибке «с точки зрения вызывающего» (это то, что Carp :: carp позволяет делать в Perl).

РЕДАКТИРОВАТЬ: Для ясности, этот вопрос не касается LBYL и EAFP, а также предварительных условий или программирования по контракту. Прошу прощения, если я произвел такое неверное впечатление.Этот вопрос касается того, как произвести обратную трассировку, начиная с нескольких (одного, двух) уровней стека вызовов.

EDIT2: модуль Python traceback - очевидное место для поиска Python-эквивалента Perl Carp :: carp , но после его изучения в течение некоторого времени я не смог найти способ использовать его для того, что я хочу делать. FWIW, Perl's Carp :: carp позволяет точно настроить начальный кадр для трассировки, выставив глобальную (следовательно, с динамической областью видимости) переменную $ Carp :: CarpLevel . Библиотечные функции, не относящиеся к API, которые могут вычислить -out, local -ize и увеличить эту переменную при входе (например, local $ Carp :: CarpLevel + = 1; ). Я не вижу ничего даже отдаленно вроде этого модуля трассировки Python. Так что, если я что-то не пропустил, любое решение, использующее трассировку Python , должно было бы занять несколько иной подход ...

7
задан kjo 26 November 2011 в 12:00
поделиться