Изменение вашей функции для отображения id
объектов
def fun1(x):
print(id(x),id(y))
x = 2*x
print(id(x))
return x
In [315]: y = np.arange(3)
In [316]: id(y)
Out[316]: 140296824014768
In [317]: z = fun1(y)
140296824014768 140296824014768
140296823720096
In [318]: id(z)
Out[318]: 140296823720096
Таким образом, массив, на который ссылается y
, передается в функцию, и на него могут ссылаться как x
(переменная аргумента), так и y
(внешняя переменная). Но присвоение изменяет ссылку x
- этот объект возвращается обратно к z
. y
без изменений.
def fun2(x):
print(id(x), id(y))
x[0] = 23
print(id(x))
return x
С помощью этой 2-й функции назначение изменяет элемент x
, но не изменяет id
ссылочного объекта. y
, x
и z
все ссылаются на один и тот же массив.
In [320]: y
Out[320]: array([0, 1, 2])
In [321]: id(y)
Out[321]: 140296824014768
In [322]: z = fun2(y)
140296824014768 140296824014768
140296824014768
In [323]: id(z)
Out[323]: 140296824014768
In [324]: z
Out[324]: array([23, 1, 2])
In [325]: y
Out[325]: array([23, 1, 2])
Если мы сделаем копию y
, либо перед передачей ее в функцию, либо внутри функции, то изменение x
не изменит y
.
In [327]: y = np.arange(3)
In [328]: id(y)
Out[328]: 140296823645328
In [329]: z = fun2(y.copy())
140296823647968 140296823645328
140296823647968
In [330]: id(z)
Out[330]: 140296823647968
In [331]: z
Out[331]: array([23, 1, 2])
In [333]: y
Out[333]: array([0, 1, 2])
Тот факт, что мы передаем массив функции, не меняет необходимость в копии. У нас было бы то же поведение, даже если мы только что выполнили действие на верхнем уровне.
In [334]: y = np.arange(3)
In [335]: x = y.copy()
In [336]: x[:2]=22
In [337]: x
Out[337]: array([22, 22, 2])
In [338]: y
Out[338]: array([0, 1, 2])
Мы получаем то же поведение, если объект является списком:
In [339]: yl = [1,2,3]
In [340]: fun1(yl)
140296925836360 ...
140296824729096
Out[340]: [1, 2, 3, 1, 2, 3]
In [341]: fun2(yl)
140296925836360 ...
140296925836360
Out[341]: [23, 2, 3]
In [343]: yl
Out[343]: [23, 2, 3]