Переменные, свободные от Python. Почему это не получается? - PullRequest
7 голосов
/ 30 декабря 2011

Следующий код печатает 123:

>>> a = 123
>>> def f():
...     print a
...
>>> f()
123
>>>

Но происходит следующее:

>>> a = 123
>>> def f():
...     print a
...     a = 456
...     print a
...
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
UnboundLocalError: local variable 'a' referenced before assignment
>>>

Я ожидал, что это напечатает:

123
456

Чтоя здесь скучаю?

PS Я использую Python 2.6.6, если это имеет значение.

Ответы [ 4 ]

8 голосов
/ 30 декабря 2011

Если функция читает только из переменной, она считается глобальной. Если функция пишет в нее когда-либо, она считается локальной. Во второй функции записывается a, поэтому предполагается, что он локальный. Тогда строка выше (откуда она читается) недействительна.

Вот ссылка на FAQ по Python: http://docs.python.org/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

5 голосов
/ 30 декабря 2011

То, что вы используете, называется замыканием : вы берете переменную из внешней области видимости и заключаете в функциональный блок.

С вашим кодом все в порядке, и он будет работать в JavaScript.

К сожалению, в Python замыкания доступны только для чтения.

И ошибка всегда UnboundLocalError: local variable 'var_name' referenced before assignment, что полностью вводит в заблуждение.

Вкратце, этоэто не вы, это ограничение языка в сочетании с ошибочным сообщением об ошибке .

РЕДАКТИРОВАТЬ:

Я вижу здесь несколько человек, выступающих за использование global, , который имеетопасные побочные эффекты : вы получите доступ к переменным с тем же именем на несколько областей выше текущей, а это не то, что вам нужно для замыканий.

Решение было добавлено в Python 3 сnonlocal Ключевое слово, которое именно это и делает: перепривязать переменную из внешней области во внутреннюю область.

Существует способ имитировать нелокальный код для Python 2.x , но на самом деле вылучше просто неприсвойте что-нибудь своей переменной: скопируйте значения, верните значения, измените на месте только изменяемые типы, и все будет в порядке.

5 голосов
/ 30 декабря 2011

Это потому, что Python автоматически действует так, как будто переменная является глобальной, если вы не определите или не попытаетесь изменить ее в функции.Попробуйте добавить global a в ваш код.

>>> a = 123
>>> def f():
...     global a
...     print a
...     a = 456
...     print a
... 
>>> f()
123
456
>>> a
456

В первом примере вы не определили и не изменили, так что это был глобальный пример.Но если вы хотите, например, добавить 20 к a, вы также должны использовать global a.

Также имейте в виду, что функция a in f является глобальной, и ее значение будет отличаться послеВыполнение функции f.

Если вы хотите создать локальную переменную, помните, что объявление всегда идет перед чтением, поэтому print a нельзя сделать до a = 456.

РЕДАКТИРОВАТЬ: Хорошо, в то время как мы говорим о замыканиях и опасно использовать глобальные, есть и другая возможность.

>>> a = 123
>>> def f():
...     b = a
...     print b
...     b = 456
...     print b
... 
>>> f()
123
456
>>> a
123
>>> 

Здесь мы используем возможность замыкания только для чтения, чтобы сделать копию а, а затем изменить эту копию,без изменения внешней переменной a КАК ДОЛГО, КАК ЭТО ИНТЕГЕР.Помните, что b содержит ссылку на a.Если a является, например, списком, а операция f похожа на b.append(3), то и a, и b будут доступны и изменены вне области действия.

Выбор изМетод отличается в зависимости от потребностей.

0 голосов
/ 05 февраля 2013

Место для комментариев слишком мало, чтобы поместиться в приведенные ниже цитаты, поэтому я отправляю новый ответ здесь.

Я думаю, что это проблема переменной области. В Модель исполнения документа Python написано:

Если операция привязки имени происходит где-либо в блоке кода, все Использование имени в блоке рассматривается как ссылка на текущий блок. Это может привести к ошибкам, когда имя используется внутри блок, прежде чем он будет связан. Это правило неуловимо. Python не хватает объявления и позволяет операции привязки имени происходить где угодно внутри блока кода. Локальные переменные блока кода могут быть определяется путем сканирования всего текста блока на предмет привязки имени операции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...