2012-09-08 18 views
3

我一直在使用Python創建自己的上下文管理器。我看到一些奇怪的行爲很可能是由於我的實施。在代碼體內調用上下文管理器退出

我看到__exit__代碼在'with'上下文中調用語句之前調用。例如,下面是代碼片段:

with ProgressBar(10) as p: 
    p.update(1) 

,它的異常:

Traceback (most recent call last): 
    File "<stdin>", line 3, in <module> 
AttributeError: 'NoneType' object has no attribute 'update' 

我把調試在我所有的上下文管理器的__enter____exit__和更新方法。在update()之前調用__exit__。這沒有意義,所以我必須錯過簡單的事情。

這裏是我的簡單情況管理器類:

class ProgressBar(object): 
    """Progress bar that normalizes progress to [0 - 100] scale""" 

    def __init__(self, max_value): 
     """Create progress bar with max_value""" 

     self._current_value = 0.0 
     self._completed_value = 100.0 
     self._max_value = float(max_value) 
     print 'init', max_value 

    def __enter__(self): 
     """Start of context manager, 'with' statement""" 

     print 'enter' 
     self._current_value = 0.0 

    def __exit__(self, exc_type, exc_value, traceback): 
     """Start of context manager, 'with' statement""" 

     print 'exit' 
     self._current_value = self._completed_value 

     # Not handling any exceptions, so they'll be raised automatically 
     # To ignore exceptions return True or inspect arguments to handle 

     return False 

    def update(self, value): 
     """Update progress value""" 

     print 'update' 
     if value >= self._max_value: 
      self._current_value = 100 
     else: 
      self._current_value = (value/self._max_value) * self._completed_value 

     print '\r%s' % (self._current_value), 

回答

8

從文檔:

object.__enter__(self)

輸入與此相關的運行時環境。 with語句 會將此方法的返回值綁定到語句的 as子句中指定的目標(如果有)。

你沒有從__enter__返回任何東西(因此你一直都會返回None)。如果您return self,你會得到

init 10 
enter 
update 
10.0 exit 
1

with語句結合上下文管理__enter__ method的變量返回值。在你的情況下,這意味着p綁定到None(你的__enter__根本沒有返回語句,因此None是默認值),則會引發AttributeError,並調用__exit__方法。

的解決方案是從__enter__方法返回self

def __enter__(self): 
    """Start of context manager, 'with' statement""" 

    print 'enter' 
    self._current_value = 0.0 
    return self 
+0

啊哈哈!謝謝。我知道這很簡單。 –