LINUX.ORG.RU

Python, странный warning


0

0

def f():
    x = 0
    def g():
        x = x + 1
    return g

g = f()
g()

Версия интерпретатора 2.5
При запуске выдает

Traceback (most recent call last):
  File "pybug.py", line 8, in <module>
    g()
  File "pybug.py", line 4, in g
    x = x + 1
UnboundLocalError: local variable 'x' referenced before assignment

Кто-нибудь может объяснить, чё за хрень?
anonymous

Привет anonymous!Есть книга по Python у меня, и там написано следующее:

Исключение UnboundLocalError возбуждается в случае, когда идет обращение к локальной переменной, которой еще не было присвоено значение. Является подклассом NameError. Следующий пример демонстрирует типичный повод для данного исключения.

def bad_function(x): if x == 0: v = 1 else: v = v+x return v

Теперь вводим следующее: print bad_function(0)

Ответ питоновского интерпретатора:1

А теперь говорим питоновскому интерпретатору это:print bad_function(1)

И он нам отвечает: Traceback (most recent call last) File "<stdin>", line 1? in ? File "<stdin>", line 5, in bad_function UnloadLocalError: Local variable 'v' referenced before assignment На русском звучит так: переменная 'v' использована до присваивания

Здесь присваивание происходит в альтернативной ветке оператора if и потому переменная оказывается непроинициализированной.

# Текст книги на этом заканчивается

Если хочешь проверить пример скопируй его код, нажми <Enter>(чтобы получить приглошение интерпретатора) и введи "bad_function(1)".Проверенно!:)

linuxi
()
Ответ на: комментарий от linuxi

Ой!Извини, с табуляторами что-то не то на linux.org.ru! Код таков:

def bad_function(x): if x == 0: v = 1 else: v = v+x return v

Не знал же я что тут нужны пробелы:(

linuxi
()
Ответ на: комментарий от linuxi

Опять двадцать пять!!! Что ж такое?!

Ну извини, с кодом не получиться:((((((((((((((((( Ну ничего, почитай и наладь у себя ошибку:)

P/S Я тоже программы пишу только на Python и знаю как обидно когда интерпретатор выдает непонятные ошибки:))

linuxi
()

К сожалению, ограничения на closures в питоне таковы, что внутри closure ты можешь читать переменную, но при попытке присваивания интерпретатор решит что это новая переменная (как в твоем случае) или создаст новую переменную.

Обходной путь - использовать список, который является единственым mutable sequence в питоне:

def f():

x = [0]

def g():

x[0] = x[0] + 1

return g

других путей я не знаю (ну еще можно отказаться от использования closure =))

burivuh
()
Ответ на: комментарий от burivuh

>ты можешь читать переменную

ты можешь читать внешнюю переменную

burivuh
()
Ответ на: комментарий от burivuh

Спасибо, понятно.

Блин, а меня глюкануло. Оно ведь не варнинг, а эксепшен выдало даже.

>ну еще можно отказаться от использования closure =))

Лучше откажусь от использования Питона :)

anonymous
()
Ответ на: комментарий от burivuh

>Или ты хочешь даунгрейдиться до Java/C# ? =)

От них в ближайшем будушем не избавлюсь всё равно :) А Питон полез смотреть как альтернативу Схеме (MzScheme частенько юзаю). Вот, собственно, с кавалерийского наскока нарвался на сабж.

anonymous
()
Ответ на: комментарий от anonymous

А =)

Ну нам в свое удалось заменить Java/C# питоном. В общем-то теперь рады все. А каждый раз теперь когда вижу код на подобных языках сижу и радуюсь за себя =)

А ским ради удовольствия? Просто язык совсем не мейнстримовый. Для промышленной разработки вряд ли сгодится =)

burivuh
()

А можно поинтересоваться что должен (по идеи автора) делать приведённый выше код?

Davidov ★★★★
()
Ответ на: комментарий от burivuh

>А ским ради удовольствия?

В основном да. На работе применял в утилитарных целях, да и то полуподпольно :)

anonymous
()
Ответ на: комментарий от Davidov

>можно поинтересоваться что должен (по идеи автора) делать приведённый выше код?

Дык, хотя бы не генерировать эксепшен. Просто экспериментировал с closure. Так ведь мало что лямбды кастрированые, еще и closure туда же...

anonymous
()
Ответ на: комментарий от anonymous

>Дык, хотя бы не генерировать эксепшен.

try - except? :)

Если я правильно понимаю, то просто дело в непонимании того,
как работают области видимости.

Вот пример:

>>> x=1
>>> def a():
...  x=x+1
... 
>>> a()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 2, in a
UnboundLocalError: local variable 'x' referenced before assignment

Присваивание x, насколько я понимаю,
создаёт локальную переменную.

И что всё-таки вы имели в виду?
x в вашем коде должна быть
статической переменной (в терминах C)?

Davidov ★★★★
()
Ответ на: комментарий от Davidov

>И что всё-таки вы имели в виду?

def make_weird_closure():
    x = 199
    def get_x(): return x
    def inc_x(): x = get_x() + 1
    def dispatch(m):
        return { "get_x" : get_x, "inc_x" : inc_x }[m]
    return dispatch

c = make_weird_closure()
print c("get_x")()
c("inc_x")()
c("inc_x")()
print c("get_x")()

Печатает:
199
199

Т.е. имя переменной x, в зависимости от ее местоположения (l-value или r-value), с какого-то бодуна соответвует разным участкам памяти.
Отсюда впечатление (может быть ошибочное) что Питон дизайнили левой пяткой. 

Так понятней, что имелось в виду?

anonymous
()
Ответ на: комментарий от anonymous

>Т.е. имя переменной x, в зависимости от ее местоположения
>(l-value или r-value), с какого-то бодуна соответвует разным участкам памяти.

Ну логика, насколько я понимаю, в том, что l-value автоматом создаёт local variable. А r-value входит в closure.

>Отсюда впечатление (может быть ошибочное) что Питон дизайнили левой пяткой. 

У всех свои представления о дизайне. Мне вот такой (работающий) вариант кажется
намного более логичным. Сразу понятно, "кто на ком стоял".


davidov@theatre:~/tmp/python$ cat 1.py
def make_weird_closure():
    make_weird_closure.x = 199
    def get_x(): return  make_weird_closure.x
    def inc_x():
		make_weird_closure.x = get_x() + 1
    def dispatch(m):
        return { "get_x" : get_x, "inc_x" : inc_x }[m]
    return dispatch

c = make_weird_closure()
print c("get_x")()
c("inc_x")()
c("inc_x")()
print c("get_x")()
davidov@theatre:~/tmp/python$ python 1.py
199
201

Davidov ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.