2013-03-17 64 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