Ответ 1
Нет, это не так: содержание статьи finally
не зависит от механики возврата; если вы хотите увидеть, какое значение будет возвращено, вам придется делать то, что вы упомянули, и явно сохранить его где-нибудь в области видимости.
У меня есть оператор return внутри предложения try
:
def f():
try:
return whatever()
finally:
pass # How do I get what `whatever()` returned in here?
Можно ли получить возвращаемое значение внутри предложения finally
?
Это скорее теоретический вопрос, поэтому я не ищу обходного пути, как сохранение его в переменной.
Нет, это не так: содержание статьи finally
не зависит от механики возврата; если вы хотите увидеть, какое значение будет возвращено, вам придется делать то, что вы упомянули, и явно сохранить его где-нибудь в области видимости.
Вам обязательно нужно "войти" после инструкции return?
Изменения, разрешенные перед оператором, все sys.settrace() - это все, что вам нужно.
Только после возврата:
Я думаю, что в безплатном Python вы должны это сделать. "нитки" могут быть маринованными в стеках, и должно быть возвращено значение, которое должно быть возвращено, как вершина стека значений.
В CPython я еще не нашел способ заглянуть наверху стека значений.
Конечно, все возможно с ctypes или c-level extension, здесь быстрая демонстрация:
"""
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()
Работает с Python-2.7.2 в 64-битном режиме, поставляемом с osx:
air:~ dima$ python valuestack.py
return 0.959725159294
caught 0.959725159294
Это невозможно. Это может быть, если вы считаете гигантские халявные хаки, например, проверяете байт-код и возитесь с объектом рамки. Я не уверен, что это даже имеет смысл, так как возвращаемое значение не находится в локальном режиме, и я не думаю, что вы можете получить доступ к стеку промежуточных значений (где сохраняется возвращаемое значение) через объекты фрейма.
Возможно, вы можете использовать ctypes
плюс API C, но это, вероятно, будет очень шатким, а также потребует очень хорошо знакомого с реализацией finally
. Я не знаю достаточно отдаленно об этом, чтобы судить, насколько это возможно, но само собой разумеется, что это будет прямо за пределами того, что может сделать код Python.
И затем добавлена проблема, что может не быть возвращаемого значения (если whatever()
выдает исключение)! Я думаю, вы могли бы легко обнаружить это условие, используя sys.exc_info()
.
def f():
InvalidFoo = object()
foo = InvalidFoo
try:
foo = whatever()
return foo
finally:
if foo is not InvalidFoo:
# look at foo