15. Danh sách, bộ dữ liệu và mảng

Danh sách, bộ dữ liệu và các đối tượng giống như mảng biểu thị các bộ sưu tập có thứ tự. Tất cả chúng đều hỗ trợ quyền truy cập được lập chỉ mục, nhưng chúng có các mô hình lưu trữ, quy tắc có thể thay đổi và sự đánh đổi hiệu suất khác nhau.

Danh sách là một chuỗi các tham chiếu đối tượng có thể thay đổi.

Tuple là một chuỗi bất biến của các tham chiếu đối tượng.

Một đối tượng giống như mảng lưu trữ dữ liệu được gõ nhỏ gọn hoặc hiển thị bộ đệm liền kề.

Những khác biệt này rất quan trọng vì bộ chứa CPython lưu trữ các tham chiếu trừ khi loại đó được thiết kế riêng cho việc lưu trữ thô.

15.1 Bộ sưu tập đã đặt hàng

Python có một số loại bộ sưu tập được sắp xếp.

Loại Có thể thay đổi Cửa hàng Công dụng chính
list Tài liệu tham khảo đối tượng Trình tự có thể thay đổi chung
tuple Không Tài liệu tham khảo đối tượng Bản ghi cố định, nhóm bất biến
array.array Giá trị gõ thô Lưu trữ số nhỏ gọn
bytes Không Byte thô Dữ liệu nhị phân bất biến
bytearray Byte thô Dữ liệu nhị phân có thể thay đổi
memoryview Phụ thuộc vào chế độ xem Chế độ xem bộ đệm thô Truy cập bộ đệm không sao chép

Một danh sách và một bộ dữ liệu có thể lưu trữ các đối tượng thuộc bất kỳ loại nào:python xs = [1, "two", object()] t = (1, "two", object()) Một mảng lưu trữ các giá trị của một loại cấp độ máy:```python from array import array

nums = array("i", [1, 2, 3])


Danh sách CPython lưu tr các con tr ti các đối tượng Python.

V mt khái nim:```text
PyListObject
    PyVarObject header
        ob_size = logical length
    ob_item ----> array of PyObject *
    allocated = capacity
```Vì:```python
xs = [10, 20, 30]
```cách b trí là:```text
list object
    ob_size = 3
    allocated >= 3
    ob_item ----+
                |
                v
              [ptr][ptr][ptr]
                |    |    |
                v    v    v
               10   20   30
```Danh sách không cha ti trng s nguyên. Nó lưu tr các tham chiếu đến các đối tượng s nguyên.

Đây là lý do ti sao mt danh sách có th cha các loi hn hp:```python
xs = [1, "hello", None, []]
```Mi v trí phn t đều có cùng cách biu din: a`PyObject *`.

## 15.3 Độ dài và dung lượng danh sách

Mt danh sách có độ dài logic và dung lượng được phân b.```text
length
    number of active elements

capacity
    number of slots currently allocated in the internal array
```Ví d:```python
xs = []
xs.append("a")
xs.append("b")
xs.append("c")
```Độ dài logic là 3. Dung lượng được phân b có th ln hơn 3.

Dung lượng d phòng này cho phép ni thêm hiu qu. CPython thường không thay đổi kích thước mng bên trong trên mi phn b sung. Nó phát trin mng theo các bước ln hơn.

V mt khái nim:```text
append item
    if length < allocated:
        store item in spare slot
        length += 1
    else:
        allocate larger array
        copy references
        store item
        length += 1
```Danh tính đối tượng ca danh sách vn n định. Mng phn t bên trong có th di chuyn.```python
xs = []
before = id(xs)

for i in range(1000):
    xs.append(i)

after = id(xs)
print(before == after)   # True
```## 15.4 Nối thêm danh sách`list.append`thêm một tham chiếu đối tượng vào cuối.```python
xs = []
xs.append(1)
xs.append(2)
``` cp độ C, ni thêm phi:```text
ensure there is enough capacity
increment the appended object's reference count
store the object pointer
increase the logical size
```Việc thêm một đối tượng không sao chép nó.```python
item = []
xs = []
xs.append(item)

item.append(1)
print(xs)        # [[1]]
```Danh sách lưu trữ một tham chiếu đến`item`.

## 15.5 Phân bổ quá mức danh sách

Việc phân bổ quá mức danh sách là lý do khiến việc bổ sung lặp lại có hiệu quả.

Nếu không phân bổ quá mức, vòng lặp này sẽ sao chép toàn bộ mảng trên nhiều lần lặp:```python
xs = []
for i in range(1_000_000):
    xs.append(i)
```Với việc phân bổ quá mức, CPython sẽ tăng công suất lên nhiều vị trí cùng một lúc. Công thức chính xác là chi tiết triển khai, nhưng hành vi cung cấp phần bổ sung theo thời gian không đổi được khấu hao.

Kết quả quan trọng:

| Hoạt động |     Chi phí trung bình |
| ------------------ | ---------------: |
|`append`           | `O(1)`khấu hao |
|`pop()`từ cuối |`O(1)`|
| lập chỉ mục ngẫu nhiên |`O(1)`|
| chèn ở phía trước |`O(n)`|
| xóa từ giữa |`O(n)`|

Việc bổ sung là rẻ vì nó chạm đến điểm cuối. Việc chèn ở phía trước rất tốn kém vì nhiều tài liệu tham khảo phải di chuyển.

## 15.6 Lập chỉ mục danh sách

Lập chỉ mục danh sách là truy cập mảng trực tiếp.```python
x = xs[i]
```Về mặt khái niệm:```text
check bounds
read ob_item[i]
return referenced object
```Điều này mang lại`O(1)`truy cập.

Các chỉ số phủ định được dịch:```python
xs[-1]
```có nghĩa:```text
xs[len(xs) - 1]
```sau khi xử lý giới hạn.

Lập chỉ mục trả về một tham chiếu đến đối tượng được chứa. Nó không sao chép đối tượng đó.```python
xs = [[1], [2]]
a = xs[0]
a.append(99)

print(xs)        # [[1, 99], [2]]
```## 15.7 Phân công danh sách

Việc gán mục danh sách sẽ thay thế một tham chiếu được lưu trữ.```python
xs = [1, 2, 3]
xs[1] = "two"
```Ở cấp độ C, việc thay thế phải xử lý số lượng tham chiếu một cách an toàn:```text
increment new item
store new item pointer
decrement old item
```Trật tự an toàn quan trọng khi đối tượng mới và đối tượng cũ có thể là cùng một đối tượng.

Về mặt khái niệm:```c
Py_INCREF(new_item);
old_item = items[index];
items[index] = new_item;
Py_DECREF(old_item);
```Điều này duy trì sự bất biến về quyền sở hữu ngay cả khi các công cụ hoàn thiện chạy trong`Py_DECREF`.

## 15.8 Cắt danh sách

Cắt lát sẽ tạo ra một danh sách mới.```python
xs = [[1], [2], [3]]
ys = xs[0:2]
```Danh sách mới chứa các tham chiếu đến các đối tượng phần tử giống nhau.```python
ys[0].append(99)

print(xs)    # [[1, 99], [2], [3]]
print(ys)    # [[1, 99], [2]]
```Đây là một bản sao nông.

Danh sách bên ngoài là mới. Các đối tượng chứa được chia sẻ.```text
xs ----> [ptr A][ptr B][ptr C]
ys ----> [ptr A][ptr B]
```Một bản sao sâu yêu cầu sao chép đệ quy:```python
import copy

ys = copy.deepcopy(xs)
```## 15.9 Chèn và xóa danh sách

Chèn vào giữa sẽ di chuyển các tham chiếu sau.```python
xs = [1, 2, 3, 4]
xs.insert(1, "x")
```Về mặt khái niệm:```text
[1][2][3][4]
insert at index 1
[1]["x"][2][3][4]
```Các phần tử từ chỉ số 1 trở đi dịch chuyển sang phải.

Xóa từ ca giữa bên trái:```python
del xs[1]
```Những hoạt động này được`O(n)`vì chúng có thể di chuyển nhiều con trỏ.

Bản thân các đối tượng không được sao chép. CPython di chuyển các tham chiếu bên trong mảng bên trong.

## 15.10 Sắp xếp danh sách`list.sort`sắp xếp danh sách tại chỗ.```python
xs = [3, 1, 2]
xs.sort()

sorted(xs)tạo một danh sách mới:python ys = sorted(xs) CPython sử dụng Timsort để sắp xếp danh sách. Nó ổn định, có nghĩa là các khóa bằng nhau vẫn giữ nguyên thứ tự tương đối của chúng.```python items = [ ("a", 2), ("b", 1), ("c", 2), ]

items.sort(key=lambda x: x[1]) print(items) # [('b', 1), ('a', 2), ('c', 2)]


## 15.11 Tuples Lưu trữ tài liệu tham khảo nội tuyến

Mt tuple là mt chui bt biến.

V mt khái nim:```text
PyTupleObject
    PyVarObject header
        ob_size = length
    ob_item[0]
    ob_item[1]
    ...
```Vì:```python
t = (10, 20, 30)
```cách b trí là:```text
tuple object
    ob_size = 3
    ob_item[0] ---> 10
    ob_item[1] ---> 20
    ob_item[2] ---> 30
```Không ging như danh sách, các mc trong b d liu được lưu tr ni tuyến như mt phn ca vic phân b b d liu. Không có mng có th thay đổi kích thước riêng bit.

Điu này có th thc hin được vì độ dài ca b d liu không th thay đổi sau khi to.

## 15.12 Tính bất biến của bộ dữ liệu

Tính bt biến ca b d liu có nghĩa là các tham chiếu mc ca b d liu không th thay đổi.```python
t = (1, 2, 3)
t[0] = 99        # TypeError
```Đối tượng tuple vn lưu tr các tham chiếu. Nếu mt đối tượng được tham chiếu có th thay đổi thì đối tượng đó có th thay đổi.```python
t = ([],)
t[0].append("x")

print(t)         # (['x'],)
```Tuple vn tr đến cùng mt danh sách. Danh sách đã thay đổi.

S khác bit này rt quan trng đối vi vic băm.```python
hash((1, 2, 3))      # works
hash(([],))          # TypeError
```Mt b d liu ch có th băm được nếu tt c các phn t đều có th băm được.

## 15.13 Tạo bộ dữ liệu

Tuple nghĩa đen là ph biến:```python
t = (1, 2, 3)
```Ch riêng du ngoc đơn không to ra mt b d liu. Du phy có.```python
a = (1)
b = (1,)

print(type(a))   # int
print(type(b))   # tuple
```B d liu được s dng nhiu trong ni b để:```text
function arguments
multiple return values
constant groups
dictionary keys
bytecode constants
C API argument packing
```Bi vì các b d liu là bt biến và nh gn nên chúng là nơi cha t nhiên cho các nhóm c định.

## 15.14 Đóng gói và giải nén Tuple

Python s dng b d liu để đóng gói nhiu giá tr.```python
point = 10, 20
```Điu này to ra mt tuple.

Gii nén các phn t trích xut:```python
x, y = point
``` cp độ bytecode, vic đóng gói và gii nén có các hướng dn riêng vì chúng ph biến.

Gii nén m rng:```python
first, *middle, last = [1, 2, 3, 4, 5]
```to mt danh sách cho mc tiêu được gn du sao.```python
print(middle)    # [2, 3, 4]
```## 15.15 Danh sách so với bộ dữ liệu

Danh sách và b d liu có hành vi lp ch mc tương t nhưng mc tiêu thiết kế khác nhau.

| Tính năng | Danh sách | B d liu |
| ---------- | ------------------------ | ------------------------ |
| Kh năng thay đổi | Có th thay đổi | Bt biến |
| Chiu dài | Có th thay đổi | Đã sa |
| Lưu tr | Mng có th thay đổi kích thước riêng bit | Tài liu tham kho mc ni tuyến |
| Ni thêm | Có | Không |
| Có th băm | Không | Nếu các phn t có th băm được |
| Công dng chính | Trình t có th thay đổi | Nhóm hoc bn ghi c định |
| Cú pháp |`[1, 2]`                 | `(1, 2)`|

S dng danh sách khi b sưu tp thay đổi.

S dng b d liu khi b sưu tp đại din cho mt nhóm c định.

## 15.16 Mảng lưu trữ giá trị thô`array.array`lưu trữ các giá trị được gõ nhỏ gọn, không phải tham chiếu đối tượng Python.```python
from array import array

xs = array("i", [1, 2, 3])
```Mã loi kim soát biu din cp độ C.

Ví d:

| Nhp mã | Ý nghĩa |
| --------- | -------------- |
|`"b"`| char đã ký |
|`"B"`| ký t không du |
|`"h"`| ký ngn |
|`"H"`| ngn không du |
|`"i"`| đã ký int |
|`"I"`| int không du |
|`"l"`| ký dài |
|`"L"`| không du dài |
|`"f"`| phao |
|`"d"`| đôi |

Mt mng s nguyên nh gn hơn nhiu so vi danh sách các đối tượng s nguyên trong Python.

V mt khái nim:```text
list of ints
    [ptr][ptr][ptr]
      |    |    |
      v    v    v
     int  int  int

array("i")
    [raw int][raw int][raw int]
```## 15.17 Sự đánh đổi mảng

Mng nh gn nhưng ít tng quát hơn danh sách.

| Tính năng | Danh sách |`array.array`|
| --------------------- | --------------------------------------------- | ---------------------------- |
| Các loi phn t | Bt k đối tượng Python nào | Mt kiu nguyên thy |
| S dng b nh | Cao hơn | H |
| Tính cô đọng v s | Nghèo | Tt |
| Phương thc đối tượng Python | Tài liu tham kho đối tượng đầy đủ | Giá tr được chuyn đổi ti ranh gii |
| D liu không đồng nht | Có | Không |
| Giao thc đệm | Không s dng b đệm s thô trc tiếp như mng | Có |

Mng rt hu ích cho I/O nh phân, lưu tr s nh gn và d liu tương thích vi b đệm.

Đối vi tính toán s nng, các mng ca bên th ba như mng NumPy thường mnh hơn.

## 15,18 byte dưới dạng mảng byte`bytes`là một chuỗi byte bất biến.```python
b = b"abc"

print(b[0])     # 97
```Nó hot động ging như chui nhưng lưu tr byte thô.`bytearray`là phiên bn có th thay đổi:```python
buf = bytearray(b"abc")
buf[0] = 65

print(buf)      # bytearray(b'Abc')
```Đối vi d liu nh phân,`bytes`Và`bytearray`nh gn hơn`list[int]`.

```python
data = [97, 98, 99]     # list of Python int objects
raw = b"abc"            # compact bytes
```## 15.19 Chế độ xem bộ nhớ và Cắt không sao chép

A`memoryview`có th hin th chế độ xem vào b đệm hin có.```python
buf = bytearray(b"abcdef")
view = memoryview(buf)[2:5]

print(view.tobytes())   # b'cde'
```Chế độ xem không sao chép các byte cơ bn.

Vic thay đổi thông qua chế độ xem có th ghi s nh hưởng đến nhà xut khu:```python
buf = bytearray(b"abcdef")
view = memoryview(buf)

view[0] = ord("X")

print(buf)              # bytearray(b'Xbcdef')
```Điu này hu ích cho các trình phân tích cú pháp nh phân, giao thc mng, định dng tp và mô-đun m rng.

## 15.20 Giao thức tuần tự

Danh sách, b d liu, byte, mng byte, phm vi và mng tham gia vào hành vi trình t.

Các thao tác chung:```python
len(xs)
xs[i]
xs[i:j]
x in xs
for x in xs:
    ...
```Loi quyết định cách thc hin các hot động đó.

 cp độ C, hành vi trình t được th hin thông qua các khe trình t như:```text
sq_length
sq_item
sq_ass_item
sq_contains
sq_concat
sq_repeat
```Trình t bt biến b qua các v trí phân công.

Trình t có th thay đổi cung cp hành vi chuyn nhượng.

## 15.21 Lặp lại

Trình lp danh sách lưu tr tham chiếu đến danh sách và ch mc hin ti.```python
xs = [1, 2, 3]
it = iter(xs)

print(next(it))    # 1
```V mt khái nim:```text
list iterator
    sequence reference
    current index
```Vic lp li mt b d liu cũng tương t.

Lp li danh sách s thy đối tượng danh sách ch không phi bn sao nh chp nhanh.```python
xs = [1, 2, 3]

for x in xs:
    if x == 2:
        xs.append(4)
```Vic thay đổi danh sách trong quá trình lp có th to ra hành vi khó hiu. Tránh nó tr khi hành vi được kim soát có ch ý.

## 15.22 Kiểm tra tư cách thành viên

Đối vi mt danh sách hoc b d liu:```python
x in xs
```thc hin quét tuyến tính.

V mt khái nim:```text
for each item:
    compare item == x
```Đây là`O(n)`.

Đối vi khi lượng công vic nng v thành viên, hãy s dng mt b hoc lnh:```python
seen = set(xs)

if x in seen:
    ...
```Mt tp hp s dng hàm băm và thường cho kết qu trung bình`O(1)`thành viên.

## 15.23 Sao chép

Danh sách các phương pháp sao chép còn nông cn:```python
a = [[1], [2]]

b = a.copy()
c = list(a)
d = a[:]
```C ba đều to ra mt danh sách bên ngoài mi. Các đối tượng bên trong được chia s.```python
b[0].append(99)

print(a)    # [[1, 99], [2]]
```Sao chép b d liu thường tr v cùng mt đối tượng khi không cn bn sao thc:```python
t = (1, 2, 3)
u = tuple(t)

print(t is u)    # True
```Bi vì các b d liu là bt biến nên vic s dng li này là an toàn.

## 15.24 Lặp lại

Trình t lp li lp li các tài liu tham kho.```python
xs = [[]] * 3
xs[0].append(1)

print(xs)        # [[1], [1], [1]]
```C ba v trí đều tr đến cùng mt danh sách bên trong.

Đúng mu:```python
xs = [[] for _ in range(3)]
```Bây gi mi phn t là mt danh sách khác nhau.

Đây là s c v mô hình tham chiếu ch không phi li nhân danh sách.

## 15.25 Sắp xếp danh sách đối tượng

Sp xếp s dng so sánh hoc mt chc năng chính.```python
items = ["aaa", "b", "cc"]
items.sort(key=len)
```Vi`key`, CPython tính toán các khóa và sp xếp bng cách s dng các khóa đó.

Điu này tránh vic tính toán li nhiu ln logic so sánh đắt tin.

Sp xếp n định cho phép sp xếp nhiu lượt:```python
items.sort(key=lambda x: x.name)
items.sort(key=lambda x: x.group)
```Sau ln sp xếp th hai, các mc có nhóm bng nhau s gi nguyên th t tên t ln sp xếp đầu tiên.

## 15.26 Hiểu danh sách

Vic hiu danh sách s xây dng mt danh sách trc tiếp.```python
squares = [x * x for x in range(10)]
```Nó thường nhanh hơn và rõ ràng hơn các vòng lp ni thêm th công đối vi các phép biến đổi đơn gin.

Hình dng tương đương:```python
squares = []
for x in range(10):
    squares.append(x * x)
```S hiu biết có các mu mã byte chuyên dng và gi cho thân vòng lp nh gn.

## 15.27 Biểu thức trình tạo so với Danh sách

Vic hiu danh sách s to ra tt c các phn t ngay lp tc.```python
xs = [x * x for x in range(1_000_000)]
```Mt biu thc trình to to ra các giá tr mt cách lười biếng.```python
it = (x * x for x in range(1_000_000))
```S dng danh sách khi bn cn lp ch mc, truyn ti lp li hoc d liu c th hóa.

S dng trình to khi bn cn mt lượt và mun tránh lưu tr tt c kết qu.

## 15.28 Các mẫu hiệu suất phổ biến

| Nhim v | La chn tt hơn | Lý do |
| ------------------------ | ---------------------- | -------------------------- |
| Ni nhiu mc |`list.append`| Khu hao`O(1)`|
| Xây dng t lp li |`list(iterable)`| Đường dn xây dng hiu qu |
| Bn ghi c định |`tuple`| Bt biến và nh gn |
| Kim tra tư cách thành viên |`set`| Tra cu da trên hàm băm |
| Xếp hàng t trái |`collections.deque`| Pop trái hiu qu |
| Lưu tr s nh gn |`array.array`hoc NumPy | Lưu tr đánh máy thô |
| D liu nh phân |`bytes`hoc`bytearray`| Lưu tr byte nh gn |
| Ct nh phân không sao chép |`memoryview`| Tránh phân b |
| Nhiu ni |`join`| Tránh sao chép nhiu ln |

Danh sách có mc đích chung. Chúng không ti ưu cho mi khi lượng công vic được đặt hàng.

##15.29 Những lỗi thường gặp

Mt s li ph biến xut phát trc tiếp t mô hình vùng cha da trên tham chiếu ca CPython.

Danh sách bên trong được chia s:```python
matrix = [[0] * 3] * 3
```Tt hơn:```python
matrix = [[0] * 3 for _ in range(3)]
```S dng tư cách thành viên danh sách cho các b tra cu ln:```python
if user_id in user_ids_list:
    ...
```Tt hơn:```python
user_ids = set(user_ids_list)
if user_id in user_ids:
    ...
```Xóa trước nhiu ln:```python
while xs:
    xs.pop(0)
```Tt hơn:```python
from collections import deque

q = deque(xs)
while q:
    q.popleft()
```Ni chui hoc byte lp li:```python
s = ""
for part in parts:
    s += part
```Tt hơn:```python
s = "".join(parts)
```## 15.30 Bản phác thảo API C

To danh sách:```c
PyObject *list = PyList_New(0);
if (list == NULL) {
    return NULL;
}
```Ni thêm:```c
PyObject *item = PyLong_FromLong(42);
if (item == NULL) {
    Py_DECREF(list);
    return NULL;
}

if (PyList_Append(list, item) < 0) {
    Py_DECREF(item);
    Py_DECREF(list);
    return NULL;
}

Py_DECREF(item);

PyList_Appendtăng tham chiếu mục nội bộ. Tài liệu tham khảo thuộc sở hữu địa phương vẫn phải được phát hành.

Tạo bộ dữ liệu:```c PyObject *tuple = PyTuple_New(1); if (tuple == NULL) { return NULL; }

PyObject *item = PyLong_FromLong(42); if (item == NULL) { Py_DECREF(tuple); return NULL; }

PyTuple_SET_ITEM(tuple, 0, item);


`PyTuple_SET_ITEM`ăn cp tài liu tham kho. Đừng`Py_DECREF(item)`sau khi s dng thành công.

S khác bit này là mt trong nhng by s hu API C c đin.

## 15.31 Mô hình tinh thần

S dng mô hình này:```text
list
    mutable sequence
    separate resizable array of PyObject *
    over-allocates for efficient append

tuple
    immutable sequence
    inline fixed array of PyObject *
    compact for fixed groups

array
    mutable typed sequence
    raw value storage
    compact but homogeneous

bytes
    immutable raw byte sequence

bytearray
    mutable raw byte sequence

memoryview
    zero-copy view over buffer-exporting object
```Đối vi danh sách và b d liu, hãy nh rng các phn t là tham chiếu. Sao chép vùng cha không sao chép các đối tượng bên trong nó.

## 15.32 Tóm tắt

Danh sách và b d liu là vùng cha tham chiếu. Danh sách có th thay đổi và s dng mng có th thay đổi kích thước được phân b riêng. Mt b d liu là bt biến và lưu tr các tham chiếu mc ni tuyến theo phân b có kích thước c định.

Mng và các đối tượng ging byte lưu tr d liu thô nh gn thay vì tham chiếu đến các đối tượng Python tùy ý. Chúng phù hp hơn vi d liu nh phân và lưu tr s được đánh máy.

Vic hiu các b cc này s gii thích hu hết các hành vi v hiu sut và độ chính xác: hiu qu ni thêm, chi phí chèn phía trước, bn sao nông, cm by tham chiếu lp li, tính bt biến ca b d liu, chế độ xem b đệm và s khác bit gia vùng cha đối tượng chung và b lưu tr thô nh gn.