0

Python プロジェクトで使用されている単純な AssertTrue 関数があり、その出力を変更して、呼び出し元のコード ステートメントを出力したいと考えました。コードは次のようになります。

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) が期待どおりに動作しないのか疑問に思っています)

4

1 に答える 1

2

トレースバックは複数行の関数呼び出しを処理しませんか?

多くの関数は、数十行または (恐ろしい) 数百行の長さです。トレースバックが関数全体を出力した場合、スタック トレースは理解できないほど長くなります。ですから、あなたが見ているのは、物事をクリーンで最小限に保つための試みだと思います.

同様の質問に対するいくつかの回答をまとめました。

inspect は関数全体のソースしか取得できないことを考慮して (ソースがパス上で利用可能な場合)、これを提供できます。

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')
于 2012-07-17T10:19:22.093 に答える