2010-04-09 4 views
13

У меня есть такой код:Python вложенная функция прицелы

def write_postcodes(self): 
    """Write postcodes database. Write data to file pointer. Data 
    is ordered. Initially index pages are written, grouping postcodes by 
    the first three characters, allowing for faster searching.""" 
    status("POSTCODE", "Preparing to sort...", 0, 1) 
    # This function returns the key of x whilst updating the displayed 
    # status of the sort. 
    ctr = 0 
    def keyfunc(x): 
     ctr += 1 
     status("POSTCODE", "Sorting postcodes", ctr, len(self.postcodes)) 
     return x 
    sort_res = self.postcodes[:] 
    sort_res.sort(key=keyfunc) 

Но СУУ реагирует с NameError:

Traceback (most recent call last): 
    File "PostcodeWriter.py", line 53, in <module> 
    w.write_postcodes() 
    File "PostcodeWriter.py", line 47, in write_postcodes 
    sort_res.sort(key=keyfunc) 
    File "PostcodeWriter.py", line 43, in keyfunc 
    ctr += 1 
UnboundLocalError: local variable 'ctr' referenced before assignment 

Как я могу это исправить? Я думал, что невесты позволят мне это сделать. Я пробовал использовать «глобальный», но он все еще не работает.

+0

также смотрите на этот вопрос: http://stackoverflow.com/questions/2516652/scoping-problem-in-recursive-closure –

ответ

19

Поскольку вложенная функция не может перепроверять нелокальное имя (в Python 2, в Python 3, вы должны использовать оператор nonlocal, чтобы включить это), вам необходимо выполнить инкремент без перезаписи barename (путем сохранения счетчика как элемент или атрибут некоторого barename, не как само имя бармена). Например:

... 
ctr = [0] 
def keyfunc(x): 
    ctr[0] += 1 
    status("POSTCODE", "Sorting postcodes", ctr, len(self.postcodes)) 
    return x 
... 

и, конечно, использовать ctr[0] везде, где вы используете голую ctr в настоящее время в другом месте.

+1

Это похоже на «взломать». Я буду использовать его, но это похоже на ограничение Python 2.x. Думаю, я скоро буду использовать 3.x. –

+0

Alex - спасибо - эта проблема была связана с тем, что функциональная композиция была беспорядочной в 2.x – Ben

5

От http://www.devshed.com/c/a/Python/Nested-Functions-in-Python/1/

Code in a nested function's body may access (but not rebind) local variables of an outer function, also known as free variables of the nested function.

Итак, вам нужно будет пройти ctr в keyfunc явно.

+0

Я попытался выполнить def keyfunc (x, k = ctr), а затем выполнил k + = 1. Но это не может работать, потому что тогда k становится частью локальной области действия функции и не обновляет внешнюю переменную ctr. –

+0

Обновление 'ctr' должно выполняться в своем собственном объеме. Вы можете обновить его до или после вызова 'keyfunc'. – danben

+0

Это было бы невозможно, так как это аргумент для сортировки() и вызывается внутренними компонентами Python, а не мной напрямую. Я не мог поместить его в лямбда либо потому, что лямбды только допускают выражения afaik. –

0

Как насчет объявления ctr вне класса, которому принадлежит write_postcodes, или любого другого класса/функции? Это сделает переменную доступной и доступной для записи.

+1

Да, но это немного грязно, имея глобальные переменные только для одной или двух функций - лучше держать их в локальные области, чтобы вы знали, почему вы их там положили. –

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