обзор ошибки в рекурсивном закрытии

почему делает эту работу:

def function1():                                                                                                             
       a = 10                                                                                                                    
       def function2():
          print a
       function2()

но это не делает:

def function1():
    a = 10
    def function2():
        print a
        a -= 1
        if a>0:
           function2()
    function2()

Я получаю эту ошибку:

UnboundLocalError: local variable 'a' referenced before assignment
9
задан Ruggero Turra 3 April 2013 в 23:58
поделиться

3 ответа

Ошибка не выглядит описательной. коренной проблемы. Майк объясняет сообщения, но это не объясняет основную причину.

Актуальная проблема заключается в том, что в python вы не можете назначать закрытые переменные. Таким образом, в function2 "a" доступно только для чтения. Когда вы назначаете его, вы создаете новую переменную, которую, как указывает Майк, вы читаете, прежде чем писать.

Если вы хотите присвоить объект внешней переменной из внутренней области видимости, вам нужно схитрить следующим образом:

def function1():
    al = [10]
    def function2():
        print al[0]
        al[0] -= 1
        if al[0]>0:
           function2()
    function2()

Итак, al неизменяемо, но его содержимое - нет, и вы можете изменить их, не создавая новую переменную.

14
ответ дан 4 December 2019 в 09:36
поделиться

Следует отметить, что это сбой синтаксиса в Python . Сам Python (на уровне байт-кода) может нормально назначать эти переменные; в 2.x просто нет синтаксиса, указывающего на то, что вы хотите это сделать. Предполагается, что если вы назначаете переменную на уровне вложенности, вы имеете в виду, что она будет локальной для него.

Это огромный недостаток; возможность назначать замыкания является фундаментальной. Я несколько раз работал над этим с помощью Charlieb's hack.

Python 3 исправляет это с помощью очень неудобно названного ключевого слова «нелокальный»:

def function1():
    a = 10
    def function2():
        nonlocal a
        print(a)
        a -= 1
        if a>0:
           function2()
    function2()
function1()

Очень плохо, что этот синтаксис доступен только в 3.x; большинство людей застревают в версии 2.x и вынуждены продолжать использовать хаки для решения этой проблемы. Это крайне необходимо перенести на 2.x.

http://www.python.org/dev/peps/pep-3104/

5
ответ дан 4 December 2019 в 09:36
поделиться

В нерабочем фрагменте вы присваиваете a, когда говорите "a -= 1". Поэтому внутри function2, a является локальным для этой области видимости, а не для охватывающей области видимости. Закрытия в Python лексические - они не ищут динамически a во фрейме function2 и, если он не был назначен, идут и ищут его во фрейме function1.

Заметьте, что это совсем не зависит от рекурсивности или использования замыканий. Рассмотрим пример этой функции

def foo():
    print a
    a = 4

Вызвав ее, вы также получите UnboundLocalError. (Без a = 4 она либо использует глобальное a, либо, если его нет, вызовет NameError). Поскольку a потенциально может быть присвоен в этой области видимости, он является локальным.


Если бы я разрабатывал эту функцию, я бы использовал подход, более похожий на

def function1():
    a = 10
    def function2(a=a):
        print a
        a -= 1
        if a > 0:
           function2(a)
    function2()

(или, конечно, for a in xrange(10, -1, -1): print a ;-) )

3
ответ дан 4 December 2019 в 09:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: