2013-03-17 65 views
0

我在一個循環中多次執行一個動作,並想知道我有多遠。我正在嘗試製作一個進度報告功能,該功能應該如下所示:Python中的閉包 - 一個例子

def make_progress_report(n): 
    i = 0 
    def progress_report(): 
     i = i + 1 
     if i % n == 0: 
      print i 
    return progress_report 

pr = make_progress_report(2) 
pr() 
pr() # 2 
pr() 
pr() # 4 

此代碼不起作用。具體來說,我得到UnboundLocalErrori。我應該如何修改它以便它可以工作?

+0

@delnan正確的,我會四處搜尋,但還有約收我沒看過這麼多問題商場。我是否應該修改您鏈接的問題中的代碼並將其粘貼到此處? – jclancy 2013-03-17 20:53:18

回答

3

這裏有3個選項:

  1. 使用清單的抗辯:

    def make_progress_report(n): 
        i = [0] 
        def progress_report(): 
         i[0] = i[0] + 1 
         if i[0] % n == 0: 
          print i[0] 
        return progress_report 
    
  2. 使用itertools.count跟蹤您的計數器:

    from itertools import count 
    def make_progress_report(n): 
        i = count(1) 
        def progress_report(): 
         cur = i.next() 
         if cur % n == 0: 
          print cur 
        return progress_report 
    
  3. 使用外地您的計數器(Python的3+而已!):

    def make_progress_report(n): 
        i = 0 
        def progress_report(): 
         nonlocal i 
         i = i + 1 
         if i % n == 0: 
          print i 
        return progress_report 
    
+0

使用列表的原因是否與數字相反,因爲列表是可變的? – jclancy 2013-03-17 21:35:41

+2

是...是的。基本上,從內部範圍內,Python不會讓你在外部範圍內重新分配任何變量,所以你不能直接將'i'重新分配給'i + 1'。當你修改列表時,對列表的引用保持不變,只有其內容發生變化。 – Gerrat 2013-03-17 21:40:32

0

再看看你是如何定義你的封閉。

#!/usr/env python 
def progressReportGenerator(n): 
    def returnProgress(x): 
     if x%n == 0: 
      print "progress: %i" % x 
    return returnProgress 

complete = False 
i = 0 # counter 
n = 2 # we want a progress report every 2 steps 

getProgress = progressReportGenerator(n) 

while not complete: 
    i+=1 # increment step counter 

    # your task code goes here.. 

    getProgress(i) # how are we going? 

    if i == 20: # stop at some arbtirary point... 
     complete = True 
     print "task completed" 
2

你可以考慮使用一個發電機:

def progress_report(n): 
    i = 0 
    while 1: 
     i = i+1 
     if i % n == 0: 
      print i 
     yield # continue from here next time 

pr = progress_report(2) 

next(pr) 
next(pr) 
next(pr) 
next(pr) 
0

所以是Progress_Report不通過變量關閉的n應在定義關閉......看看下面的例子中傳遞一世。你可以這樣檢查它...

>>> def make_progress_report(n): 
...  i=0 
...  def progress_report(): 
...    i += 1 
...    if i % n == 0: 
...      print i 
...  return progress_report 
... 
>>> pr = make_progress_report(2) 
>>> pr.__closure__ 
(<cell at 0x1004a5be8: int object at 0x100311ae0>,) 
>>> pr.__closure__[0].cell_contents 
2 

你會注意到只有一個項目在關閉pr。這是您最初通過的價值ni值不是閉包的一部分,因此在函數定義之外,i不在範圍之內。

這裏是用Python閉包的一個很好的討論:http://www.shutupandship.com/2012/01/python-closures-explained.html