是否可以在上下文管理器的__exit __()方法内访问上下文对象(代码块)?
我想在 exit
()方法中再次引发该代码对象,如果它引发异常(可能多次,可能会有延迟)。我知道使用装饰器很容易,但是我的动机是有时我只想重复一些我不想提取的代码片段,并将其装饰到一个单独的函数中。我正在寻找以下方面的东西:
class again(object):
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is not None:
???? # Invoke the code object again
return True # eat exception
它会像这样使用:
x = 0
with again():
print x
x += 1
if x == 1:
raise Exception('I hate 1')
预期的输出将是:
0
1
我可以找到一种掌握代码对象的方法。上下文管理器属性似乎都没有引用它(我想它并不是真正需要的,因为它的工作只是在做事前后)。
有可能做到吗?
-
该
with
块不作为单独的代码对象存在,所以不存在。看到类似的问题。在那种情况下,发问者正试图做相反的事情(从代码块内部访问上下文管理器),但是正如此答案所解释的,该with
块不是单独的作用域,因此它实际上没有任何单独的状态。您可以通过一个示例看到它:
import contextlib import dis @contextlib.contextmanager def silly(): yield def foo(): print "Hello" with silly(): print "Inside" print "Goodbye"
接着
>>> dis.dis(foo.__code__) 2 0 LOAD_CONST 1 (u'Hello') 3 PRINT_ITEM 4 PRINT_NEWLINE 3 5 LOAD_GLOBAL 0 (silly) 8 CALL_FUNCTION 0 11 SETUP_WITH 10 (to 24) 14 POP_TOP 4 15 LOAD_CONST 2 (u'Inside') 18 PRINT_ITEM 19 PRINT_NEWLINE 20 POP_BLOCK 21 LOAD_CONST 0 (None) >> 24 WITH_CLEANUP 25 END_FINALLY 5 26 LOAD_CONST 3 (u'Goodbye') 29 PRINT_ITEM 30 PRINT_NEWLINE 31 LOAD_CONST 0 (None) 34 RETURN_VALUE
您可以看到该
with
块的代码以及其他所有内容都位于该函数的代码对象内。它不作为单独的代码对象存在,也没有与函数的其余代码区分开。您无法以任何理智的方式获取它(我的意思是,无需破解字节码)。