我在try
子句中有一个return语句:
def f():
try:
return whatever()
finally:
pass # How do I get what `whatever()` returned in here?
是否可以在finally
子句中获取返回值?
这更像是一个理论问题,所以我不是在寻找一种解决方法,比如将它保存到变量中。
答案 0 :(得分:13)
不,它不是 - finally
子句的内容独立于返回机制;如果你想查看返回的值,你必须像你提到的那样做,并明确地将它保存在范围内的某个地方。
答案 1 :(得分:5)
你是否必须在退货声明后“进入”?
在语句之前允许更改,sys.settrace()就是您所需要的。
仅在退货后:
我认为,在无堆栈Python中,你应该能够做到这一点。 “线程”可以在无堆栈中进行腌制,并且即将返回的值(也就是值堆栈的顶部)应该存在。
在CPython中,我还没有找到一种方法来查看价值堆栈的顶部。
当然,通过ctypes或c-level扩展可以实现一切,这是一个快速演示:
"""
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
答案 2 :(得分:1)
这是不可能的。如果你考虑巨大的怪异黑客,比如检查字节码和摆弄框架对象,可能。我不确定这个是否有意义,因为返回值不在本地,我认为你不能通过帧对象访问中间值的堆栈(这是保存返回值的位置)。
也许您可以使用ctypes
加上C API,但这可能非常不稳定,并且需要非常熟悉实现finally
。我不太清楚它是否可以判断它是多么可行,但不用说,这完全不属于 Python 代码所能做的。
然后还有一个问题,即可能不是返回值(如果whatever()
抛出异常)!我想你可以使用sys.exc_info()
轻松检测到这种情况。
答案 3 :(得分:1)
def f():
InvalidFoo = object()
foo = InvalidFoo
try:
foo = whatever()
return foo
finally:
if foo is not InvalidFoo:
# look at foo