Многострочные выражения Python и трассировка стека

У нас есть простая функция AssertTrue, используемая в нашем проекте Python, и я хотел изменить вывод, который она предоставляет, чтобы напечатать оператор кода, из которого она была вызвана. Код выглядит примерно так:

1 import traceback
2
3 def AssertTrue(expr, reason=None):
4     print traceback.format_stack()[-2]
5
6 AssertTrue(1 == 2,
7         reason='One is not equal to two')

Выход:

File "/tmp/fisken.py", line 7, in <module>
  reason='One is not equal to two')

Мне интересно, почему traceback.format_stack дает мне код только в строке 7. Оператор начинается со строки 6, и выражение, которое я хотел бы видеть в выводе, также находится в той же строке. Разве отслеживание не обрабатывает многострочные вызовы функций?

(Не берите в голову, что есть более эффективные способы сделать AssertTrue(...). Мне просто интересно, почему traceback.format_stack (и.extract_stack) не ведет себя так, как я ожидал)

1 ответ

Решение

Разве отслеживание не обрабатывает многострочные вызовы функций?

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

Я собрал несколько ответов на похожие вопросы:

С учетом того, что он может проверить только источник всей функции (если источник доступен по пути), я могу предложить вам следующее:

import traceback
import inspect
import gc

def giveupthefunc(frame):
    code  = frame.f_code
    globs = frame.f_globals
    functype = type(lambda: 0)
    funcs = []
    for func in gc.get_referrers(code):
        if type(func) is functype:
            if getattr(func, "func_code", None) is code:
                if getattr(func, "func_globals", None) is globs:
                    funcs.append(func)
                    if len(funcs) > 1:
                        return None
    return funcs[0] if funcs else None


def AssertTrue(expr, reason=None):
    print traceback.format_stack()[-2]
    frame = inspect.currentframe().f_back
    func = giveupthefunc(frame)
    if func:
        source = inspect.getsourcelines(func)
        i = source[1]
        for line in source[0]:
            print i, ":", line,
            i += 1



def my_fun():
    AssertTrue(1 == 2,
             reason='One is not equal to two')

my_fun()

Который производит:

/Library/Frameworks/Python.framework/Versions/2.7/bin/python /Users/xxxx/Documents/PycharmProjects/scratchpad/test.py
  File "/Users/xxxx/Documents/PycharmProjects/scratchpad/test.py", line 35, in my_fun
    reason='One is not equal to two')

33 : def my_fun():
34 :     AssertTrue(1 == 2,
35 :              reason='One is not equal to two')
Другие вопросы по тегам