Python:是否可以访问`finally`子句中的返回值?

Ram*_*hum 12 python finally return-value

我在try子句中有一个return语句:

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

是否有可能在finally子句中获得返回值?

这更像是一个理论问题,所以我不是在寻找一种解决方法,比如将它保存到变量中.

Amb*_*ber 14

不,它不是 - 该finally条款的内容独立于返回机制; 如果你想查看返回的值,你必须像你提到的那样做,并明确地将它保存在范围内的某个地方.


Dim*_*nek 5

你是否必须在退货声明后"进入"?

语句之前允许的更改,sys.settrace()就是您所需要的.

返回后才:

我认为,在无堆栈Python中,你应该能够做到这一点."线程"可以在无堆栈中进行腌制,并且即将返回的值(也就是值堆栈的顶部)应该存在.

在CPython中,我无法找到价值堆栈顶部的方式.

  • 动态更改frame.f_lasti是不允许的
  • 动态更改frame.f_code是不允许的
  • 动态更改frame.f_trace是允许的,但似乎没有帮助
  • 在return语句"已经执行"之后,从finally块内设置跟踪函数不会捕获实际的返回事件
  • 与法令没有捕获返回值
  • 我假设调用者忽略f的返回值,因此内省或跟踪调用者没有帮助
  • 我认为无论()有副作用,不能再被调用
  • 调试器,至少那些我尝试过的,没有得到返回值(?); 用Python编写的调试器使用sys.settrace和/或最后一个异常,它们都不包含堆栈上的返回值.

当然,通过ctypes或c级扩展可以实现一切,这是一个快速演示:

"""
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()
Run Code Online (Sandbox Code Playgroud)

与osx一起提供的64位模式下的Python-2.7.2:

air:~ dima$ python valuestack.py 
return 0.959725159294
caught 0.959725159294
Run Code Online (Sandbox Code Playgroud)