В Python, почему list [] автоматически глобален? - PullRequest
9 голосов
/ 13 июня 2011

Это странное поведение.

Попробуйте это:

rep_i=0
print "rep_i is" , rep_i
def test():
  global rep_i #without Global this gives error but list , dict , and others dont
  if rep_i==0:
    print "Testing Integer %s" % rep_i
    rep_i=1
  return "Done"

rep_lst=[1,2,3]


def test2():
  if rep_lst[0]==1:
    print "Testing List %s" % rep_lst
  return "Done"


if __name__=="__main__":
  test()
  test2()

Почему список не нужно объявлять глобальным?они автоматически глобальны?

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

Ответы [ 5 ]

13 голосов
/ 13 июня 2011

Это не глобально автоматически.

Однако есть разница между rep_i=1 и rep_lst[0]=1 - первый повторяет имя rep_i, поэтому global необходим для предотвращения создания локального слота с тем же именем. В последнем случае вы просто изменяете существующий глобальный объект, который обнаруживается при обычном поиске по имени (изменение записи в списке похоже на вызов функции-члена в списке, это не привязка имени).

Чтобы проверить это, попробуйте назначить rep_lst=[] в test2 (т.е. установить его в новый список). Если вы не объявите rep_lst global, эффекты не будут видны за пределами test2, поскольку создается локальный слот с тем же именем и затеняет глобальный слот.

5 голосов
/ 13 июня 2011

Вам нужно использовать global, только если вы присваиваете глобальное имя.Без global назначение создает новый локальный объект.

Нет ничего особенного в том, как global применяется к списку - global просто влияет на область действия и разрешение имен.

3 голосов
/ 13 июня 2011

В python есть ошибка с именем UnboundLocalError, которая часто сбивает с толку новичков. Заблуждение таково: будущее назначение меняет способ поиска переменной.

Когда интерпретатор видит имя переменной в первый раз, он смотрит вперед до конца текущего блока кода, и если у вас нет присвоения ему где-либо в пределах того же блока кода, интерпретатор считает его глобальным , Однако, если вы это сделаете, то он считается локальным, и любая ссылка на него до присвоения генерирует UnboundLocalError. Это ошибка, которую вы получили. Вот почему вам нужно объявить global rep_i. Если вы не указали rep_i, вам не понадобится эта строка.

Кроме того, это не имеет ничего общего с типом переменной. Кроме того, назначение или добавление элемента в список (что вы, вероятно, хотели сделать, но не сделали) не является назначением самого списка, это, по сути, вызов метода для объекта списка, который отличается от назначения: назначение создает новый объект (возможно, под именем, которое уже существует), а манипулирование списком просто изменяет существующий список. Вы можете попробовать:

In [1]: # It won't work with small integers, as they are cached singletons in CPython

In [2]: a = 123123

In [3]: id (a)
Out[3]: 9116848

In [4]: a = 123123

In [5]: id(a)
Out[5]: 9116740

In [6]: # See, it changed

In [7]: # Now with lists

In [8]: l = [1,2,3]

In [9]: id(l)
Out[9]: 19885792

In [10]: l[1] = 2

In [11]: id(l)
Out[11]: 19885792

In [12]: # See, it is the same

In [13]: # But if i reassign the list, even to the same value

In [14]: l = [2,2,3]

In [15]: id(l)
Out[15]: 19884272
2 голосов
/ 13 июня 2011

Вот пример, который демонстрирует, что переменная, отличная от list / dict, доступна в подпрограмме, и проблема, как все говорят, заключается в действии rebinding в исходном примере кода:

x = 1
def test():
    y = x + 1
    print y
test()

Вы увидите, что это напечатано 2, несмотря на то, что x не объявлено глобальным.

2 голосов
/ 13 июня 2011

Если бы вы присвоили новое значение rep_lst внутри test2 (а не только одному из его элементов, как вы это сделали), оно не будет работать без флага global. В Python, если вы не присваиваете переменную внутри функции, она будет искать эту переменную в более глобальных областях, пока не найдет ее.

Например, в этом сегменте кода я определяю список как глобально, так и внутри example(). Поскольку переменная в example() ближе по объему к example2(), чем глобальная, это то, что будет использоваться.

x = ["out"]

def example():
    x = ["in"]
    def example2():
        print x # will print ["in"]

Это не имеет ничего общего со списками, но это поведение любой переменной в Python.

...