Значение ndarray a, полученное из b.diagonal(), изменилось после модификации b

Меня немного смущает поведение приведенного ниже кода, и мне интересно, может ли кто-нибудь пролить свет на этот вопрос. По сути, у меня есть матрица под названием mat, которая является пустой ndarray. Я получаю его диагональ, используя mat.diagonal(), и присваиваю ее переменной diag. Я изменил все диагональные значения mat на 100. Теперь я обнаружил, что все значения diag тоже изменились на 100, что, похоже, указывает на то, что diag напрямую ссылается на элементы в mat. Тем не менее, когда я проверяю адрес памяти первого элемента в diag и сравниваю его с адресом mat, они отличаются. Как правильно на это смотреть?

import numpy as np
import pandas as pd

mat_df = pd.DataFrame(data=[[1,2,3], [4,5,6], [7,8,9]])
print(mat_df)

mat = mat_df.values
diag = mat.diagonal()
print(diag)
diag_loc = np.diag_indices_from(mat)
mat[diag_loc] = 100
print(diag)

print(diag[0])
print(id(diag[0]))
print(mat[0][0])
print(id(mat[0][0]))

mat:

   0  1  2
0  1  2  3
1  4  5  6
2  7  8  9

diag:

[1 5 9]

Значения diag меняются из-за изменения mat:

[100 100 100]

первое значение diag:

100

и его адрес

139863357577488

первое значение мата:

100

и его адрес

139863376059664

Согласно документации, diagonal возвращает the returned array is a read-only view

hpaulj 07.07.2024 04:18
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
1
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не можете узнать адрес с id. Прежде всего, id не возвращает адрес (хотя реализация CPython использует адрес памяти для построения id, это всего лишь одна реализация, и это не адрес как таковой). А во-вторых, это будет только адрес объекта Python (в вашем случае того, который обертывает numpy.int64).

Этот объект Python просто создан для обертывания любых функций numpy (которые непрозрачны для Python: Python не знает, когда они должны возвращать одни и те же значения).

Простой эксперимент, который вы можете провести, чтобы убедиться, что ваш id ничего не значит.

id(diag[0])
# 139729998312368
id(diag[0])
# 139730045496016

Видите ли, даже два последовательных абсолютно идентичных вызова не возвращают один и тот же идентификатор!

diag[0] — это вызов numpy diag.__getitem__(0). Завернуты в контейнер Python, который каждый раз разный, как и результат вызова любой функции f(0), для которой нет оснований предполагать, что каждый идентичный вызов возвращает один и тот же результат.

Итак, если вы хотите знать, где на самом деле хранятся int64, вы не можете спросить Python (с его функцией id), поскольку не только для этого теперь нужен id, но, что более важно, Python не знает. Где хранятся int64 — это внутренняя проблема библиотеки numpy. Так что вам нужно спросить numpy.

Лучший способ сделать это — использовать base imho.

diag.base
#array([[100,   2,   3],
#       [  4, 100,   6],
#       [  7,   8, 100]])
diag.base is mat.base
# True

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

diag.ctypes.data
# 61579664
mat.ctypes.data
# 61579664

Или для более полной информации какие данные и как просматриваются массивом

mat.__array_interface__
# {'data': (61579664, False), 'strides': (8, 24), 'descr': [('', '<i8')], 'typestr': '<i8', 'shape': (3, 3), 'version': 3}
diag.__array_interface__
# {'data': (61579664, True), 'strides': (32,), 'descr': [('', '<i8')], 'typestr': '<i8', 'shape': (3,), 'version': 3}

показывая, как эти двое используют одни и те же «данные», но используют разные «шаги» и «форму» для их использования.

id(): «Детали реализации CPython: это адрес объекта в памяти».
no comment 07.07.2024 04:51

Кроме того, если вы проверите diag.flags, вы увидите, что OWNDATA есть False, потому что mat является «владельцем» данных.

jared 07.07.2024 06:56

@nocomment Да, действительно. Рабочая часть здесь (та, о которой я имел в виду) — это «детали реализации». Это означает, что на практике это связано с адресом. Но теоретически это всего лишь выбор реализации, а не часть спецификации. В следующей версии это может измениться без предупреждения. И самое главное, это только для одной из реализаций (CPython). Самый распространенный, конечно. Python — это язык, а не интерпретатор и не программа (Cpython является и является наиболее распространенной программой, интерпретирующей язык Python). А язык Python ничего не говорит о том, что id является адресом.

chrslg 07.07.2024 10:53

И кроме того, в любом случае здесь, даже если спрашивающий сказал: «Я на 100% уверен, что мой код будет работать только на текущей версии интерпретатора cpython», и в этом случае было бы приемлемым хаком воспользоваться знаниями об этом. Детали реализации, использовать id все равно не получится, так как это адрес объекта, но этот объект представляет собой просто динамическую постоянно меняющуюся оболочку вокруг int64 100 и ничего не говорит о том, где 100 действительно хранится

chrslg 07.07.2024 10:56

Другие вопросы по теме