То, что мы называем представлением типизированной памяти, не является отдельным классом: в зависимости от контекста (код Cython, чистый код Python) оно меняет свою идентичность под капотом.
Так что давайте начнем с
%%cython
cdef class Temp:
cdef double[::1] inp
Здесь double[::1] inp
имеет тип __Pyx_memviewslice
, который не является объектом Python:
typedef struct {
struct {{memview_struct_name}} *memview;
char *data;
Py_ssize_t shape[{{max_dims}}];
Py_ssize_t strides[{{max_dims}}];
Py_ssize_t suboffsets[{{max_dims}}];
} {{memviewslice_name}};
Что происходит, когда мы вызываем id(self.inp)
?Очевидно, id
является чисто Python-функцией, поэтому новый временный объект Python (представление памяти) должен быть создан из self.inp
(только для возможности вызова id
) и уничтожен непосредственно после этого.Создание временного Python-объекта выполняется с помощью __pyx_memoryview_fromslice
.
Зная это, легко объяснить, почему идентификаторы одинаковы: несмотря на то, что объекты разные, временные представления памяти имеютпо совпадению тот же адрес (и, следовательно, тот же id
, который является деталью реализации CPython), потому что CPython снова и снова использует память.
В Python есть похожие сценарии, здесь является примером для объектов-методов , или даже более простым:
class A:
pass
# the life times of temporary objects don't overlap, so the ids can be the equal
id(A())==id(A())
# output: True
# the life times of objects overlap, so the id cannot be equal
a,b=A(), A()
id(a)==id(b)
# output: False
Итак, в двух словах: вы ожидаете, что один и тот же id
означает, что тот же объект неправильный,Это предположение имеет место только тогда, когда время жизни объектов перекрывается.