Изменение значений переменных в цикле for?

#python #python-3.x #for-loop #scope

#python #python-3.x #for-цикл #область видимости

Вопрос:

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

 x, y, z = 1, 2, 3

for i in [x, y, z]:
    i  = 10
    print(i)

# prints 11
# prints 12
# prints 13

print(x, y, z)
# prints 1 2 3
  

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

Комментарии:

1. Ваша проблема с пониманием заключается в том, что i на каждой итерации ссылается на определенный объект, но затем вы сразу же меняете i ссылку на другой объект значения, скажем, x 10 . Это не имеет никакого отношения к оригиналу x . Кроме того, x является неизменяемым.

Ответ №1:

На самом деле вам даже не нужно for loop , чтобы продемонстрировать это то, что вы называете проблемой, но на самом деле это не так.

Возьмем этот более простой пример:

 x = 1
i = x
i  = 10
print(x)
print(i)
  

Конечно x , не изменяется, поскольку содержит неизменяемое значение 1 .

Вот неизменяемые типы в Python:

  • все примитивные типы: int , float , bool
  • плюс tuple и str

Неизменность означает отсутствие общей ссылки. Так что, когда у вас есть: x = 1
y = 1 не означает, что x и y ссылается на одно и то же точное значение 1 , но вместо этого каждая из двух переменных имеет свой «дублирующий» экземпляр с тем же значением. Так что это изменение x вообще не влияет y .

Точно так же, когда у вас есть: x = 1
i = x это создаст «совершенно новое значение 1 » и присвоит его i , чтобы изменение i вообще не влияло на переменную x .

Но теперь, чтобы получить желаемое поведение, вы можете сделать что-то вроде:

 x, y, z = 1, 2, 3
l = [x, y, z]
for i in range(len(l)):
    l[i]  = 10
x, y, z = l
  

Или, если вы действительно хотите быть немного изворотливым, вы можете сделать:

 x, y, z = 1, 2, 3
for var in locals().keys():
    if var in ['x', 'y', 'z']:
        locals()[var]  = 10
  

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

Комментарии:

1. Спасибо за подробное объяснение! Я понимаю, что вы говорите об отсутствии общей ссылки и о том, как изменение i не влияет x . Я менее уверен, какое это имеет отношение к неизменности. Если я назначу i = 1 , разве это не неизменяемый тип? но я, тем не менее, могу позже назначить i = 10 , уступая 11 .

2. На самом деле, когда вы это делаете i = 10 , это не прямое изменение значения, но copying сначала оно выполняет calculation и, наконец reassign , результат i . Это может выглядеть примерно так: i = 1 (# initialization) temp = i (# copying) i = temp 10 (# computing then reassigning)

Ответ №2:

На самом деле это не связано с областями.

Здесь вы выполняете итерацию, используя значение i и увеличивая только значение i, а не любую из переменных x, y или z. Таким образом, x, y и z остаются неизменными.

Чтобы изменить, используйте следующее:

 b = {'x': 1,'y': 2, ,'z': 3}
for m in b.keys():
  b[m]  = 10
  

Комментарии:

1. Я думаю, OP спрашивает, почему это так.

2. @AMC объяснение также включено

3. Я не думаю, что это полная картина. Если вы выполняете итерацию по списку списков, вы можете изменять списки: l = [[1],[2]]; for j in l: j.append(4) будет изменяться l на месте

Ответ №3:

Дело в том, что i переменная похожа на «временную» переменную в for операторе. Итак, вы присваиваете i значение массива на каждой итерации. Посмотрите на следующий пример:

 array = [1, 2, 3]

for i in array:
    i  = 10 #here we are modifying the "temporary" variable
    
print(array) #prints 1 2 3

index = 0
for i in array:
    array[index]  = 10 #here we are modifying the array
    index  = 1
    
print(array) #prints 11 12 13