6.2. The ndarray¶
ndarray là kiểu dữ liệu chứa dữ liệu số trong numpy. Nó là hai thứ trong một: một khối dữ liệu đóng gói liền mạch và một bộ mô tả nhỏ ở trước khối đó cho biết cách đọc nó.
6.2.1. Bên trong hộp¶
Khối dữ liệu lưu mọi phần tử của mảng liên tiếp nhau, không có gì thêm vào giữa chúng. Mỗi phần tử chiếm cùng số byte -- một byte cho mảng giá trị uint8, hai byte cho uint16, bốn byte cho float. Một mảng uint8 256 phần tử chính xác là 256 byte dữ liệu; 256 con số đó trong một list Python chiếm một kilobyte -- mỗi giá trị một slot 32-bit bất kể giá trị thực sự cần bao nhiêu bit.
Bộ mô tả ghi lại ý nghĩa của khối. Năm giá trị là đủ để mô tả bất kỳ mảng hình chữ nhật nào, dù có bao nhiêu chiều:
dtype-- kiểu phần tử. Quyết định mỗi phần tử chiếm bao nhiêu byte và phạm vi giá trị nó có thể lưu (được đề cập trong Dtypes).itemsize-- độ rộng byte của một phần tử, được suy ra từ dtype.ndim-- số chiều (1 cho vector, 2 cho ma trận, 3 cho khối, tối đa 4).shape-- kích thước theo từng chiều dưới dạng tuple.strides-- cách bước qua khối dữ liệu để duyệt từng trục. Được đề cập trong Hình dạng và stride.
Đó là tất cả. Mọi con đường nhanh trong numpy -- số học, rút gọn, broadcasting, slicing -- đều hoạt động trực tiếp từ năm giá trị đó cộng với con trỏ dữ liệu, không có chi phí Python theo từng phần tử.
6.2.2. Lợi ích của thiết kế¶
Ba đặc tính xuất phát từ "khối đóng gói + bộ mô tả nhỏ" và định nghĩa cách phần còn lại của phần này hoạt động.
Phép toán theo từng phần tử chạy trong một lần gọi. a + b giữa hai mảng có hình dạng khớp cộng hai buffer và ghi kết quả vào buffer thứ ba, tất cả trong một lần gọi thư viện. np.sin(a) làm tương tự cho sin của mỗi phần tử. Các toán tử số học, so sánh và bit-wise đều hoạt động theo cách này.
Xem cùng dữ liệu theo cách khác là miễn phí. Yêu cầu một vùng con của mảng, hoặc cùng dữ liệu được bố trí theo hình dạng khác, không di chuyển bất kỳ byte nào. Thao tác trả về một bộ mô tả mới trỏ vào cùng khối dữ liệu. Kết quả được gọi là view -- một cửa sổ thứ hai lên cùng buffer bên dưới. Ghi qua một view sẽ ghi vào nguồn.
Hình dạng khác nhau vẫn hoạt động. Mảng ngắn hơn so với mảng dài hơn, một hàng so với ma trận, một cột so với một hàng -- numpy căn chỉnh chúng bằng broadcasting, một tập nhỏ các quy tắc quyết định trục ngắn nào được kéo dài để khớp với trục dài. Việc kéo dài là ảo; không có dữ liệu nào bị nhân đôi.
6.2.3. Chi phí của thiết kế¶
Hai hạn chế xuất phát từ cùng thiết kế.
Mọi phần tử có cùng kiểu. Một list có thể chứa int bên cạnh str bên cạnh một list gồm ba giá trị int khác; một ndarray thì không thể. Dtype được cố định tại thời điểm khởi tạo. Trang Dtypes đề cập đến tập nhỏ các kiểu mà numpy hỗ trợ và các quy tắc xuất phát từ việc cố định một kiểu.
Mở rộng mảng không miễn phí. Một list giữ các slot dự phòng ở cuối và hỗ trợ .append một cách rẻ. Một ndarray có đúng kích thước cần thiết; việc thêm phần tử có nghĩa là cấp phát buffer mới lớn hơn và sao chép nội dung cũ vào đó. Không có phương thức append(), và điều đó là có chủ ý. Cách làm đúng trên camera là cấp phát đích ở kích thước cuối cùng trước rồi điền vào; Hiệu năng đề cập kỹ thuật này.
Với buffer kiểu đóng gói cho dữ liệu, bộ mô tả nhỏ cho metadata, và ba bảo đảm hành vi (phép toán theo phần tử nhanh, view thay thế không sao chép của cùng dữ liệu, và hình dạng được broadcasting), ndarray là nền tảng mà phần còn lại của chương dựa vào. Cách một mảng thực sự được tạo ra -- từ literal, từ allocation điền sẵn, từ buffer ngoại vi -- là câu hỏi thực tế tiếp theo.