是否可以在上下文管理器的__exit __()方法内访问上下文对象(代码块)?

发布于 2021-01-29 16:34:47

我想在 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

我可以找到一种掌握代码对象的方法。上下文管理器属性似乎都没有引用它(我想它并不是真正需要的,因为它的工作只是在做事前后)。

有可能做到吗?

关注者
0
被浏览
51
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    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块的代码以及其他所有内容都位于该函数的代码对象内。它不作为单独的代码对象存在,也没有与函数的其余代码区分开。您无法以任何理智的方式获取它(我的意思是,无需破解字节码)。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看