Python: Is it possible to access the return value inside the `finally` clause?

一世执手 提交于 2021-02-07 11:38:13

问题


I have a return statement inside a try clause:

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

Is it possible to get the return value inside the finally clause?

This is more of a theoretical question, so I'm not looking for a workaround like saving it to a variable.


回答1:


No, it isn't - the finally clause's content is independent from return mechanics; if you do want to see what value is returned you'd have to do as you mentioned and explicitly save it somewhere that's in-scope.




回答2:


Do you absolutely have to "get in" after the return statement?

Changes allowed before the statement, sys.settrace() is all you need.

Only after return:

I think, in stackless Python, you should be able to do that. "threads" can be pickled in stackless, and about-to-be-returned value, aka top of value stack, ought to be there.

In CPython, I couldn't find a way peek at top of value stack yet.

  • dynamically changing frame.f_lasti is not allowed
  • dynamically changing frame.f_code is not allowed
  • dynamically changing frame.f_trace is allowed but doesn't seem to help
  • set tracing function from within finally block doesn't catch actual return event after return statement was "already executed"
  • with statment doesn't catch return value
  • I assume caller ignores f's return value, thus introspection or tracing the caller doesn't help
  • I assume whatever() has side effects and cannot be called again
  • debuggers, at least those that I tried, don't get return value (?); debuggers written in Python use sys.settrace and/or last exception, neither of these contains return value on stack.

Of course, everything is possible with ctypes or c-level extension, here's a quick demo:

"""
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()

Works with Python-2.7.2 in 64-bit mode as shipped with osx:

air:~ dima$ python valuestack.py 
return 0.959725159294
caught 0.959725159294



回答3:


It's not possible. It may be if you consider giant freaking hacks, like inspecting the bytecode and fiddling with the frame object. I'm not sure this one would even make sense, as the return value isn't in a local and I don't think you can access the stack of intermediate values (which is where the return value is saved) via frame objects.

Perhaps you can use ctypes plus the C API, but that would probably be very shaky as well, and would require being very familiar with the implementation of finally. I don't know remotely enough about it to judge how feasible this is, but needless to say, this would fall squarely outside of what Python code can do.

And then there's the added problem that there might not be a return value (if whatever() throws an exception)! I guess you could easily detect that condition though, using sys.exc_info().




回答4:


def f():
    InvalidFoo = object()
    foo = InvalidFoo
    try:
        foo = whatever()
        return foo
    finally:
        if foo is not InvalidFoo:
            # look at foo


来源:https://stackoverflow.com/questions/14034156/python-is-it-possible-to-access-the-return-value-inside-the-finally-clause

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!