2014-01-21 45 views
3

我想在出口()方法中再次调用代码对象,如果它引发异常(可能是几次,也许有延迟)。我知道使用装饰器很容易,但我的动机是有时我想重复一些我不想提取到单独函数并对其进行装饰的代码段。我在找东西沿着这些路线:是否可以在上下文管理器的__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

'code object'是什么意思? –

+0

我非常怀疑这是可能的 - 主要是因为这不是上下文管理者的目的。正如你所暗示的,python的处理方式是通过函数(可能使用装饰器)。你所描述的气味更像是红宝石给我...... – mgilson

+0

上下文管理器用于管理资源。他们从来没有被设计成“块装饰器”来任意改变代码块的功能,这正是你所期待的。 – user2357112

回答

5

with块不存在作为一个单独的代码对象,所以没有。请参阅this similar question。在这种情况下,提问者试图做相反的事情(从代码块内部访问上下文管理器),但正如this answer所解释的那样,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块的代码只是函数代码对象内与其他事情一样。它不作为单独的代码对象存在,并且与函数代码的其余部分没有区别。你不能以任何理智的方式(我的意思是,没有黑客字节码)出来。

相关问题