Python có hai loại trình tự tương tự như bộ dữ liệu và danh sách. Sự khác biệt nổi tiếng nhất giữa chúng là các bộ dữ liệu là bất biến, nghĩa là bạn không thể thay đổi kích thước cũng như các đối tượng bất biến của chúng.
Bạn không thể thay đổi các mục trong một tuple:
>>> a = [1,2,3]
>>> a[0] = 10
Traceback [most recent call last]:
File "", line 1, in
TypeError: 'tuple' object does not support item assignment
Nhưng bạn có thể thay đổi các đối tượng có thể thay đổi:
>>> b = [1,[1,2,3],3]
>>> b[1]
[1, 2, 3]
>>> b[1].append[4]
>>> b
[1, [1, 2, 3, 4], 3]
Trong nội bộ, cả danh sách và bộ dữ liệu đều được triển khai như một danh sách các gợi ý cho các đối tượng Python [các mục]. Khi bạn xóa một mục khỏi danh sách, tham chiếu đến một mục sẽ bị phá hủy. Hãy nhớ rằng, mục đã bị loại bỏ có thể sống nếu có các tài liệu tham khảo khác trong chương trình của bạn.
Bộ dữ liệu
Mặc dù thực tế là các bộ dữ liệu ít phổ biến hơn danh sách, nhưng nó là một loại dữ liệu cơ bản, được sử dụng rất nhiều nội bộ.
Bạn có thể không nhận thấy, nhưng bạn đang sử dụng Tuples khi:
- Làm việc với các đối số và tham số
- trả lại 2 hoặc nhiều mục từ một chức năng
- lặp lại các cặp giá trị khóa của từ điển
- Sử dụng định dạng chuỗi
Thông thường, một chương trình đang chạy có hàng ngàn bộ dữ liệu được phân bổ.
>>> import gc
>>> def type_stats[type_obj]:
... count = 0
... for obj in gc.get_objects[]:
... if type[obj] == type_obj:
... count += 1
... return count
...
>>> type_stats[tuple]
3136
>>> type_stats[list]
659
>>> import pandas
>>> type_stats[tuple]
6953
>>> type_stats[list]
2455
Danh sách trống so với các bộ dữ liệu trống
Tuple trống hoạt động như một singleton, nghĩa là, luôn luôn có một tuple với chiều dài bằng không. Khi tạo một python Tuple trống, chỉ ra một cái đã được phân bổ, theo cách mà bất kỳ bộ tuple trống nào cũng có cùng địa chỉ trong bộ nhớ. Điều này là có thể bởi vì các bộ dữ liệu là bất biến và đôi khi tiết kiệm rất nhiều bộ nhớ.
>>> a = []
>>> b = []
>>> a is b
True
>>> id[a]
4409020488
>>> id[b]
4409020488
Nhưng điều này không áp dụng cho danh sách vì chúng có thể được sửa đổi.
>>> a = []
>>> b = []
>>> a is b
False
>>> id[a]
4465566920
>>> id[b]
4465370632
Tối ưu hóa phân bổ cho các bộ đếm nhỏ
Để giảm phân mảnh bộ nhớ và tăng tốc độ phân bổ, Python tái sử dụng các bộ dữ liệu cũ. Nếu một tuple không còn cần thiết và có ít hơn 20 mục thay vì xóa nó vĩnh viễn, Python sẽ di chuyển nó sang free list
.
Một danh sách miễn phí được chia thành 20 nhóm, trong đó mỗi nhóm đại diện cho một danh sách các bộ dữ liệu có độ dài n
từ 0 đến 20. Mỗi nhóm có thể lưu trữ tối đa 2 000 bộ dữ liệu. Nhóm đầu tiên [không] chỉ chứa 1 phần tử và đại diện cho một tuple trống.
>>> a = [1,2,3]
>>> id[a]
4427578104
>>> del a
>>> b = [1,2,4]
>>> id[b]
4427578104
Trong ví dụ trên, chúng ta có thể thấy rằng
>>> b = [1,[1,2,3],3]
>>> b[1]
[1, 2, 3]
>>> b[1].append[4]
>>> b
[1, [1, 2, 3, 4], 3]
0 và >>> b = [1,[1,2,3],3]
>>> b[1]
[1, 2, 3]
>>> b[1].append[4]
>>> b
[1, [1, 2, 3, 4], 3]
1 có cùng ID. Đó là bởi vì chúng tôi ngay lập tức chiếm một tuple bị phá hủy trong danh sách miễn phí.Tối ưu hóa phân bổ cho danh sách
Vì danh sách có thể được sửa đổi, Python không sử dụng tối ưu hóa giống như trong các bộ dữ liệu. Tuy nhiên, danh sách Python cũng có một danh sách miễn phí, nhưng nó chỉ được sử dụng cho các đối tượng trống. Nếu một danh sách trống bị xóa hoặc thu thập bởi GC, nó có thể được sử dụng lại sau.
>>> a = []
>>> id[a]
4465566792
>>> del a
>>> b = []
>>> id[b]
4465566792
Danh sách thay đổi kích thước
Để tránh chi phí thay đổi kích thước, Python không thay đổi kích thước danh sách mỗi khi bạn cần thêm hoặc xóa một mặt hàng. Thay vào đó, mọi danh sách đều có một số vị trí trống được ẩn từ người dùng nhưng có thể được sử dụng cho các mục mới. Nếu các khe được tiêu thụ hoàn toàn Python quá nhiều không gian bổ sung cho chúng. Số lượng các vị trí bổ sung được chọn dựa trên kích thước hiện tại của danh sách.
Tài liệu nhà phát triển mô tả nó như sau:
Điều này quá mức tỷ lệ thuận với kích thước danh sách, tạo chỗ cho sự tăng trưởng bổ sung. Sự phân bổ quá mức là nhẹ nhưng đủ để cung cấp cho hành vi được khấu hao theo thời gian tuyến tính trong một chuỗi dài các lần bổ sung [] với sự hiện diện của một hệ thống thực hiện kém realloc [].
Mô hình tăng trưởng là: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
Lưu ý: new_allocated sẽ không tràn vì giá trị lớn nhất có thể là py_ssize_t_max * [9/8] + 6 luôn phù hợp với size_t.
Ví dụ: nếu bạn muốn nối một mục vào danh sách độ dài 8, Python sẽ thay đổi kích thước của nó thành 16 khe và thêm mục thứ 9. Phần còn lại của các khe sẽ được ẩn và dành riêng cho các mặt hàng mới.
Yếu tố ngày càng tăng như sau:
>>> def get_new_size[n_items]:
... new_size = n_items + [n_items // 2 ** 3]
... if n_items >> get_new_size[9]
16
Màn biểu diễn
Nếu bạn quan tâm đến so sánh tốc độ, có một bản tóm tắt tốt về hiệu suất tổng thể của Raymond Hettinger.