2.37. Named tuple và deque

List, tuple, dictionary và set đáp ứng hầu hết nhu cầu dữ liệu. Ba container khác trong mô-đun collections phù hợp với các vấn đề cụ thể mà các kiểu dựng sẵn xử lý vụng về.

2.37.1. namedtuple -- bản ghi có kiểu mà không cần lớp

Một tuple thông thường lưu trữ các giá trị theo vị trí. Điều đó ổn với một tuple nhỏ 2 hoặc 3 phần tử ngắn hạn, nhưng vượt qua đó thì point[0]point[1] bắt đầu che giấu ý nghĩa thực sự. collections.namedtuple() trả về một lớp con tuple mới có các trường được đặt tên:

>>> from collections import namedtuple
>>> Reading = namedtuple('Reading', ('temp', 'humidity', 'ts'))
>>> r = Reading(22.5, 41.0, 137204)
>>> r.temp
22.5
>>> r.humidity
41.0
>>> r[0]
22.5

Đối số fields là một chuỗi các chuỗi tên (hoặc một chuỗi được phân tách bằng khoảng trắng trong CPython; MicroPython nghiêm ngặt hơn -- hãy truyền một tuple hoặc list).

Tại sao dùng namedtuple thay vì một lớp?

  • Nó là một tuple. Lặp, giải gói, so sánh bằng, băm, và sử dụng làm khóa dict đều hoạt động miễn phí.

  • Nó bất biến. Gán lại r.temp = ... gây ra AttributeError, đó chính xác là những gì bạn muốn cho một kiểu bản ghi.

  • Nó tốn ít RAM hơn một instance lớp có cùng các trường -- bộ nhớ của tuple liên tiếp, không có __dict__.

So với lớp tương đương, một khai báo namedtuple chỉ là một dòng. Đánh đổi là các trường chỉ đọc -- để "thay đổi" một giá trị đọc, bạn tạo một cái mới.

2.37.2. deque -- bộ đệm vòng có giới hạn

Một list nhanh ở cuối (append / pop) và chậm ở đầu (insert(0, ...) / pop(0) đều dịch chuyển mọi phần tử khác). Một collections.deque nhanh ở cả hai đầu -- nó là một bộ đệm vòng được lập chỉ mục bằng con trỏ đầu và đuôi, vì vậy append và pop ở cả hai phía chạy trong cùng một lượng công việc cố định bất kể deque chứa bao nhiêu phần tử.

Khởi tạo trong MicroPython yêu cầu cả iterable ban đầu độ dài tối đa, theo thứ tự đó:

>>> from collections import deque
>>> events = deque((), 5)
>>> for i in range(8):
...     events.append(i)
>>> list(events)
[3, 4, 5, 6, 7]

Khi một deque có giới hạn đầy, mỗi append loại bỏ phần tử cũ nhất. Điều đó làm cho deque lý tưởng cho "N mẫu gần đây nhất", "N dòng log gần đây nhất", hoặc bất kỳ cửa sổ cuộn nào không cần tăng mãi.

Các phương thức được cung cấp trên deque của MicroPython được giảm thiểu có chủ đích:

  • append(x) -- thêm vào bên phải.

  • appendleft(x) -- thêm vào bên trái.

  • extend(iterable) -- thêm từng phần tử từ iterable.

  • pop() -- xóa và trả về phần tử bên phải. Gây ra IndexError khi rỗng.

  • popleft() -- xóa và trả về phần tử bên trái.

Các tính năng bị bỏ qua đáng chú ý từ deque của CPython: không có clear, count, index, remove, reverse, rotate, thuộc tính maxlen, hay __contains__. Lặp và chỉ số subscript hoạt động:

>>> events[0]
3
>>> for e in events:
...     print(e)

Một ứng dụng điển hình: giữ một vài giá trị đọc cảm biến gần đây để phát hiện thay đổi xu hướng:

history = deque((), 10)

def push(reading):
    history.append(reading)
    if len(history) == 10 and history[-1] > 2 * history[0]:
        print('reading is climbing')

2.37.3. OrderedDict -- khi thứ tự là một phần của bình đẳng

Lớp dict thông thường đã bảo toàn thứ tự chèn từ MicroPython 1.13 và CPython 3.7. Điều đó bao phủ lý do phổ biến nhất mà mọi người từng dùng collections.OrderedDict.

Những gì OrderedDict vẫn cung cấp mà dict thông thường không có:

  • Bình đẳng OrderedDict xét đến thứ tự. Hai dict thông thường so sánh bằng nhau bất cứ khi nào chúng có cùng các cặp khóa/giá trị, bất kể thứ tự chèn. Hai instance OrderedDict chỉ bằng nhau khi các cặp của chúng theo cùng thứ tự:

    >>> from collections import OrderedDict
    >>> OrderedDict([('a', 1), ('b', 2)]) == OrderedDict([('b', 2), ('a', 1)])
    False
    >>> {'a': 1, 'b': 2} == {'b': 2, 'a': 1}
    True
    
  • OrderedDict hữu ích khi bạn đang tuần tự hóa cấu hình sang định dạng quan tâm đến thứ tự khóa (TOML, một số consumer YAML), hoặc khi bạn muốn gợi ý tài liệu rõ ràng rằng thứ tự quan trọng với người đọc code của bạn.

Đối với code hàng ngày, hãy ưu tiên lớp dict dựng sẵn. Hãy dùng OrderedDict chỉ khi ngữ nghĩa thứ tự-là-một-phần-của-bình-đẳng hoặc giá trị tài liệu thực sự mang lại lợi ích.

Ba container mỗi cái có một ứng dụng hẹp. Named tuple thay thế các lớp bản ghi viết tay; deque thay thế list cho hàng đợi có giới hạn; ordered dict làm cho thứ tự chèn là một phần của hợp đồng.