Các từ điển được đặt hàng trong Python 3.6+?
Chúng được chèn theo thứ tự [1] . Kể từ Python 3.6, đối với việc triển khai CPython của Python, từ điển nhớ thứ tự các mục được chèn . Đây được coi là một chi tiết triển khai trong Python 3.6 ; bạn cần sử dụng OrderedDict
nếu bạn muốn thứ tự chèn được đảm bảo trong các triển khai Python khác (và hành vi được đặt hàng khác [1] ).
Kể từ Python 3.7 , đây không còn là chi tiết triển khai và thay vào đó trở thành một tính năng ngôn ngữ. Từ một tin nhắn python-dev của GvR :
Làm cho nó như vậy. "Dict giữ trật tự chèn" là phán quyết. Cảm ơn!
Điều này đơn giản có nghĩa là bạn có thể phụ thuộc vào nó . Các triển khai khác của Python cũng phải cung cấp một từ điển được đặt hàng chèn nếu chúng muốn là một triển khai phù hợp của Python 3.7.
Làm thế nào để 3.6
thực hiện từ điển Python thực hiện tốt hơn [2] so với cái cũ hơn trong khi duy trì trật tự phần tử?
Về cơ bản, bằng cách giữ hai mảng .
Mảng đầu tiên dk_entries
, giữ các mục ( thuộc loạiPyDictKeyEntry
) cho từ điển theo thứ tự chúng được chèn vào. Thứ tự bảo quản đạt được bằng cách này là một mảng chỉ nối thêm trong đó các mục mới luôn được chèn vào cuối (thứ tự chèn).
Thứ hai, dk_indices
giữ các chỉ số cho dk_entries
mảng (nghĩa là các giá trị chỉ ra vị trí của mục tương ứng trong dk_entries
). Mảng này hoạt động như bảng băm. Khi một khóa được băm, nó dẫn đến một trong các chỉ mục được lưu trữ dk_indices
và mục tương ứng được tìm nạp bằng cách lập chỉ mục dk_entries
. Vì chỉ giữ các chỉ mục, nên loại của mảng này phụ thuộc vào kích thước tổng thể của từ điển (từ loại int8_t
( 1
byte) đến int32_t
/ int64_t
( 4
/ 8
byte) trên các bản dựng 32
/ 64
bit)
Trong lần thực hiện trước, một mảng thưa về loại PyDictKeyEntry
và kích thước dk_size
phải được phân bổ; thật không may, nó cũng dẫn đến rất nhiều không gian trống vì mảng đó không được phép quá 2/3 * dk_size
đầy vì lý do hiệu suất . (và không gian trống vẫn có PyDictKeyEntry
kích thước!).
Đây không phải là trường hợp bây giờ vì chỉ có các mục yêu cầu được lưu trữ (những mục đã được chèn) và một mảng loại thưa intX_t
( X
tùy thuộc vào kích thước chính tả) 2/3 * dk_size
được giữ nguyên. Các không gian trống thay đổi từ loại PyDictKeyEntry
sang intX_t
.
Vì vậy, rõ ràng, việc tạo ra một mảng kiểu PyDictKeyEntry
thưa thớt đòi hỏi nhiều bộ nhớ hơn là một mảng thưa thớt để lưu trữ int
s.
Bạn có thể xem toàn bộ cuộc hội thoại trên Python-Dev liên quan đến tính năng này nếu quan tâm, đây là một bài đọc tốt.
Trong đề xuất ban đầu được thực hiện bởi Raymond Hettinger , có thể thấy một hình ảnh trực quan của các cấu trúc dữ liệu được sử dụng để nắm bắt ý chính của ý tưởng.
Ví dụ: từ điển:
d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}
hiện được lưu trữ dưới dạng [keyhash, key, value]:
entries = [['--', '--', '--'],
[-8522787127447073495, 'barry', 'green'],
['--', '--', '--'],
['--', '--', '--'],
['--', '--', '--'],
[-9092791511155847987, 'timmy', 'red'],
['--', '--', '--'],
[-6480567542315338377, 'guido', 'blue']]
Thay vào đó, dữ liệu nên được tổ chức như sau:
indices = [None, 1, None, None, None, 0, None, 2]
entries = [[-9092791511155847987, 'timmy', 'red'],
[-8522787127447073495, 'barry', 'green'],
[-6480567542315338377, 'guido', 'blue']]
Như bây giờ bạn có thể thấy, trong đề xuất ban đầu, rất nhiều không gian về cơ bản là trống để giảm va chạm và giúp việc tra cứu nhanh hơn. Với phương pháp mới, bạn giảm bộ nhớ cần thiết bằng cách di chuyển độ thưa thớt ở nơi thực sự cần thiết, trong các chỉ số.
[1]: Tôi nói "chèn theo thứ tự" và không "ra lệnh" vì, với sự tồn tại của OrderedDict, "đã ra lệnh" gợi ý thêm hành vi mà dict
đối tượng không cung cấp . OrderedDicts có thể đảo ngược, cung cấp các phương thức nhạy cảm với thứ tự và, chủ yếu, cung cấp một bài kiểm tra tính công bằng theo thứ tự ( ==
, !=
). dict
s hiện không cung cấp bất kỳ hành vi / phương pháp nào.
[2]: Việc triển khai từ điển mới thực hiện bộ nhớ tốt hơn bằng cách được thiết kế gọn hơn; đó là lợi ích chính ở đây. Tốc độ khôn ngoan, sự khác biệt không quá lớn, có những nơi mà chính quyền mới có thể đưa ra các hồi quy nhẹ ( ví dụ như tra cứu khóa ) trong khi ở những người khác (lặp đi lặp lại và thay đổi kích thước đến tâm trí) nên tăng cường hiệu suất.
Nhìn chung, hiệu suất của từ điển, đặc biệt là trong các tình huống thực tế, được cải thiện nhờ sự nhỏ gọn được giới thiệu.