Кажется, что itemsize не работает должным образом.
Да, разные результаты связаны с тем, что объект Python отличается от элемента в numpy.
В Python все является объектом. Данные «в штучной упаковке». Это означает, что, например, для int
мы получаем:
>>> sys.getsizeof(2)
28
Это 28 байтов. Это много. В большинстве языков программирования int
занимает от двух до восьми байтов. Если это 32-битный int
, то это занимает 4 байта.
Но в Python у объекта много "контекста". Например, некоторые байты используются для обозначения типа объекта и т. Д.
Numpy, однако, не реализован в Python, это не библиотека, которая сама использует объекты Python. Это больше библиотека, реализованная на C, с приятным интерфейсом для Python. Таким образом, это означает, что список [1, 4, 2, 5]
хранится не в Python как список с четырьмя ссылками на объекты int
, а как массив, как правило, с "распакованными" элементами. Таким образом, вышеприведенное займет, учитывая, что int
s занимает 32 бита каждый, 4 * 32 бита и некоторое дополнительное пространство для «контекста» вокруг массива.
Таким образом, элементы хранятся более эффективным способом. Это облегчает обработку значений, поскольку мы здесь не следуем указателям, а непосредственно непосредственно значениям (существуют способы хранения ссылок в массивном массиве, но пока будем это игнорировать). Более того, массив numpy занимает намного меньше памяти, чем эквивалентный список Python (вместе с элементами, которые он содержит).
Однако, если вы выбираете элемент из массива, для этого нужно создать объект Python. Таким образом, это означает, что здесь будет создан объект numpy.float64
, который содержит значение, но опять же много «контекста» вокруг этого значения. Это приводит к использованию большего количества памяти.
Тот факт, что numpy создает массив объектов определенного типа, также имеет некоторые последствия. Например, если вы используете numpy.int16
, то это означает, что нельзя хранить в них значения, превышающие 32767, так как это значение не может быть представлено 16-битным представлением с двумя дополнениями:
>>> np.int16(32767)
32767
>>> np.int16(32768)
-32768
Кроме того, нельзя - без использования ссылок на объекты Python или каких-либо других «хитростей» - создать массив, содержащий объекты разных типов. Numpy создает, например, массив int16
, что означает, что он интерпретирует 160 бит как 10 16-битных чисел. В Python список сам содержит ссылку на объекты, а объект Python знает, какой это тип, что означает, что мы можем установить ссылку на другой объект, другого типа.