15

try句内に return ステートメントがあります。

def f():
    try:
        return whatever()
    finally:
        pass # How do I get what `whatever()` returned in here?

finally句内で戻り値を取得することは可能ですか?

これは理論的な質問なので、変数に保存するような回避策は探していません。

4

4 に答える 4

16

いいえ、そうではありません。finally条項の内容は返品の仕組みとは無関係です。返される値を確認したい場合は、前述のようにして、スコープ内のどこかに明示的に保存する必要があります。

于 2012-12-25T21:38:00.413 に答える
6

returnステートメントの後に絶対に「入る」必要がありますか?

ステートメントのに変更が許可されている場合は、それだけで十分です。returnsys.settrace()

の値の取得return:

スタックレスPython では、それができるはずです。「スレッド」はスタックレスでピクルすることができ、値スタックのトップとも呼ばれる、返される直前の値がそこにあるはずです。

CPythonでは、値スタックのトップを覗く方法がまだ見つかりませんでした。

  • 動的に変更する frame.f_lasti は許可されていません
  • 動的に変更する frame.f_code は許可されていません
  • 動的に変更する frame.f_trace は許可されていますが、役に立たないようです
  • returnステートメントが「すでに実行された」後、finallyブロック内からトレース関数を設定すると、実際の戻りイベントがキャッチされません
  • with ステートメントは戻り値をキャッチしません
  • 呼び出し元は f の戻り値を無視すると想定しているため、呼び出し元のイントロスペクションやトレースは役に立ちません
  • what() には副作用があり、再度呼び出すことはできないと思います
  • 少なくとも私が試したデバッガーは、戻り値を取得しません (?)。Python で記述されたデバッガーは、sys.settrace および/または最後の例外を使用します。これらのいずれにも、スタック上の戻り値は含まれません。

もちろん、C レベルの拡張機能ですべてが可能です。簡単なデモを次に示しますctypes

"""
valuestack.py: Demo reading values from Python value stack
Offsets are derived for CPython-2.7.2, 64-bit, production build
"""
import ctypes, inspect, random

def id2obj(i):
    """convert CPython `id` back to object ref, by temporary pointer swap"""
    tmp = None,
    try:
        ctypes.cast(id(tmp), ctypes.POINTER(ctypes.c_ulong))[3] = i
        return tmp[0]
    finally:
        ctypes.cast(id(tmp), ctypes.POINTER(ctypes.c_ulong))[3] = id(None)

def introspect():
    """pointer on top of value stack is id of the object about to be returned
    FIXME adjust for sum(vars, locals) in introspected function
    """
    fr = inspect.stack()[1][0]
    print "caught", id2obj(ctypes.cast(id(fr), ctypes.POINTER(ctypes.c_ulong))[47])

def value():
    tmp = random.random()
    print "return", tmp
    return tmp

def foo():
    try:
        return value()
    finally:
        introspect()

if __name__ == "__main__":
    foo()

osx に同梱されている 64 ビット モードの Python-2.7.2 で動作します。

air:~ dima$ python valuestack.py 
return 0.959725159294
caught 0.959725159294
于 2012-12-26T00:28:32.253 に答える
1

不可能です。バイトコードを検査したり、フレーム オブジェクトをいじったりするなど、巨大でおかしなハックを検討している場合は、そうかもしれません。戻り値がローカルになく、フレームオブジェクトを介して中間値のスタック (戻り値が保存される場所) にアクセスできないと思うので、これが意味を成すかどうかもわかりません。

ctypesおそらくC API に加えて使用することもできますが、それもおそらく非常に不安定であり、 の実装に精通している必要がありますfinally。これがどれほど実現可能かを判断するのに十分な情報はありませんが、言うまでもなく、これはPythonコードでできることの範囲外です。

そして、戻り値がない可能性があるという追加の問題があります(whatever()例外がスローされた場合)! を使用すると、その状態を簡単に検出できると思いますsys.exc_info()

于 2012-12-25T21:39:26.133 に答える
1
def f():
    InvalidFoo = object()
    foo = InvalidFoo
    try:
        foo = whatever()
        return foo
    finally:
        if foo is not InvalidFoo:
            # look at foo
于 2012-12-26T00:43:59.117 に答える