2014-01-21 47 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塊的代碼只是函數代碼對象內與其他事情一樣。它不作爲單獨的代碼對象存在,並且與函數代碼的其餘部分沒有區別。你不能以任何理智的方式(我的意思是,沒有黑客字節碼)出來。

相關問題