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

Этот код не работает. В частности, я получаю UnboundLocalError за i. Как мне изменить его так, чтобы он работал?

+0

@delnan Правильно, я искал вокруг, но есть очень много вопросов о закрытии я не читал торговый центр. Должен ли я адаптировать код из связанного с ним вопроса и вставить его здесь? – jclancy

ответ

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

+2

Да ... иш. В принципе, изнутри внутренней области Python не позволяет повторно назначать какие-либо переменные во внешней области, поэтому вы не можете напрямую переписывать 'i'' i + 1'. Однако, когда вы изменяете список, ссылка на список остается неизменной, изменяется только ее содержимое. – Gerrat

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 не закрывается по переменному я. Вы можете проверить это так ...

>>> 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 

Вы заметите, что в закрытии пр. Есть только один элемент. Это значение, которое вы передали изначально для n. Значение i не является частью замыкания, поэтому вне определения функции i больше не входит в объем.

Вот хорошее обсуждение закрытия в Python: http://www.shutupandship.com/2012/01/python-closures-explained.html

Смежные вопросы