Какова логика этого назначения: понимание операций присваивания на месте в numpy - PullRequest
2 голосов
/ 09 октября 2019

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

a = np.ones(5)
b = torch.from_numpy(a)
a=np.add(a, 1, out=a)
print(a)
print(b)

[out]:

[2. 2. 2. 2. 2.]

тензор ([2, 2., 2., 2., 2.], dtype = torch.float64)

a = np.ones(5)
b = torch.from_numpy(a)
a=a+1
print(a)
print(b)

[out]:

[2. 2. 2. 2. 2.]

тензор ([1, 1., 1., 1., 1.], dtype = torch.float64)

Почемуне изменился ли b во втором случае?

1 Ответ

2 голосов
/ 09 октября 2019

В первом случае и a, и b совместно используют одну и ту же память (т. Е. b является представлением a или, другими словами, b указывает на значение (массив), где a также указывает на), а аргумент out гарантирует, что та же самая память a будет обновлена ​​после завершения операции np.add(). В то время как во втором случае a является новой копией, когда вы делаете a = a+1, а b все еще указывает на старое значение a.

Попробуйте второй случай с:

a += 1

и обратите внимание, что и a, и b действительно обновлены.

In [7]: a = np.ones(5) 
   ...: b = torch.from_numpy(a) 
   ...: a += 1   

In [8]: a  
Out[8]: array([2., 2., 2., 2., 2.])

In [9]: b 
Out[9]: tensor([2., 2., 2., 2., 2.], dtype=torch.float64)

Как @ hpaulj удачно указал в его комментарии , когда мы делаем a = a+1, создается новый объект и a теперь будет указывать на этот новый (массив) объект вместо старого, на который все еще указывает b. И по этой причине (массив) значение из b не обновляется.


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

...