#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