Путаница в области видимости переменных Python - PullRequest
7 голосов
/ 03 марта 2011

Я наткнулся на какой-то код, который меня озадачил. Вот минимальный пример, который показывает это:

# of course, the ... are not part of the actual code
some_var = {"key1":"value1" ... "keyN":"valueN"}

def some_func():
   v = some_var["key1"]

Код работает, но тот факт, что я могу получить доступ к some_var, прямо смущает меня. В прошлый раз, когда мне приходилось писать код на Python, я помню, что писал some_func так:

def some_func():
   global some_var
   v = some_var["key1"]

Я использую Python 2.7.1 на ПК с Windows 7. Что-то изменилось в версии 2.7, что позволяет это сделать?

Ответы [ 6 ]

6 голосов
/ 03 марта 2011

Нет, вы просто не можете переназначить some_var в локальной области.Рассмотрим следующее:

some_var = {}
def some_func():
    # some_var[5] = 6
    some_var = {1:2}
    some_var[3] = 4
some_func()
print (repr(some_var)) # {}

Вы увидите, что присвоение в some_func фактически создает локальную переменную, которая скрывает глобальную переменную.Следовательно, раскомментирование строки приведет к UnboundLocalError - вы не сможете получить доступ к переменным, пока они не определены.

3 голосов
/ 03 марта 2011

Существует разница между использованием (например, вызовом или использованием в выражении) имени из внешней области видимости и назначением его (и есть разница между назначением пустой переменной и назначением члена объекта, на который указывает переменная - x.y = ... и x[...] = ... считаются вызовами метода!).

Вам нужно только объявить, что переменная из внешней области видимости, если вы ее переназначаете.В Python 2 вы можете сделать это только с глобальными переменными (через global var), в Python 3 вы можете сделать это для абстрагированных вложенных областей (например, замыканий), используя nonlocal var.

Используя нелокальную переменную какв вашем примере не требуется global.Это происходит, однако, как только вы присваиваете переменную (с вышеупомянутым определением присваивания) где-нибудь в этой области видимости - поэтому добавьте строку some_var = ... после строки, где вы ее используете, и вы получите UnboundLocalError,Обратитесь к документации для получения подробностей.

3 голосов
/ 03 марта 2011

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

Вложенная область действия была введена в Python 2.1 включена по умолчанию в Python 2.2 ) (выделено):

Проще говоря, когда данному имени переменной не присвоено значение в функции (с помощью присваивания или операторов def, class или import), ссылки на переменная будет ищется в локальном пространстве имен охватывающей области . Более подробное объяснение правил и анализ реализации можно найти в PEP .

2 голосов
/ 03 марта 2011

Вам нужно использовать global, только если вы намереваетесь присвоить переменную, для чтения переменной это не нужно .Это различие не является произвольным, хотя может показаться, что оно выглядит на первый взгляд.

При чтении значения интерпретатор может просто искать локальную переменную с именем some_var, если он не может ее найти, он ищетглобальная переменная этого имени.Это простая и прямолинейная семантика.

При назначении значений переменной интерпретатору необходимо знать, намереваетесь ли вы назначить локальную переменную some_var или глобальную переменную. Интерпретатор предполагает, что some_var = 2 при вызове внутри функции присваивает локальную переменную, это имеет смысл, поскольку это наиболее распространенный случай .Для относительно редких случаев, когда вы хотите назначить глобальную переменную из функции, вы используете глобальный модификатор global some_var = 2.

1 голос
/ 04 марта 2011

Присвоение значения имени делает имя локальным, если имя явно не объявлено глобальным.

a = 12

def foo():
   a = 42
   print a   # uses local

foo()
>>> 42

def foo():
   global a
   a = 42

foo()
print a
>>> 42

Если имя не назначено, оно является глобальным.

a = 12

def foo():
   print a   # uses global

foo()
>>> 12

Короче говоря, вам нужно только явно объявить имя глобальным, если вы будете присваивать ему имя. Если вы просто читаете из него, вы можете использовать его по своему желанию. Однако, если вы когда-либо назначите переменную, она будет считаться локальной в этой функции, если вы не объявили ее глобальной.

b = 5

def foo():
   print b
   b = 7

foo()
>>> ???

Поскольку b назначено в foo() и не объявлено глобальным, Python решает во время компиляции , что b является локальным именем. Поэтому b является локальным именем во всей функции, , включая в операторе print перед присваиванием.

Следовательно, оператор print выдает ошибку, поскольку локальное имя b не было определено!

1 голос
/ 03 марта 2011

Зависит от использования переменной в функции Ошибка области видимости переменной Python

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