在return语句之后你一定要“进入”吗?
如果在return 语句之前允许更改,则您只需要sys.settrace()。
在 return:
之后获取值
我认为,在 stackless Python 中,您应该能够做到这一点。 “线程”可以在无堆栈中腌制,并且即将返回的值,也就是值堆栈的顶部,应该在那里。
在 CPython 中,我还没有找到查看值堆栈顶部的方法。
- 不允许动态改变 frame.f_lasti
- 不允许动态改变 frame.f_code
- 允许动态更改 frame.f_trace,但似乎没有帮助
- 从 finally 块中设置跟踪函数在 return 语句“已执行”后未捕获实际返回事件
- with 语句不捕获返回值
- 我假设调用者忽略了 f 的返回值,因此自省或跟踪调用者没有帮助
- 我认为whatever() 有副作用,不能再次调用
- 调试器,至少我尝试过的那些,没有得到返回值(?);用 Python 编写的调试器使用 sys.settrace 和/或 last 异常,它们都不包含堆栈上的返回值。
当然,一切皆有可能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()
在 osx 附带的 64 位模式下与 Python-2.7.2 一起使用:
air:~ dima$ python valuestack.py
return 0.959725159294
caught 0.959725159294