13. Triển khai đối tượng tích hợp
13. Triển khai đối tượng tích hợp
Các đối tượng tích hợp là cấu trúc dữ liệu cụ thể đằng sau các kiểu lõi của Python. Chúng là các đối tượng Python thông thường theo nghĩa là chúng có danh tính, loại, số lượng tham chiếu, thuộc tính được hỗ trợ và hành vi được xác định bởi các vị trí loại. Chúng đặc biệt vì việc lưu trữ và hoạt động của chúng được triển khai trực tiếp trong C.
Chương này cung cấp một bản đồ rộng. Các chương sau sẽ đi sâu hơn vào các chuỗi, danh sách, bộ dữ liệu, từ điển, bộ, số, hàm, mô-đun và khung.
13.1 Phần dựng sẵn là đối tượng kiểu
Một loại tích hợp nhưlist, dict, hoặcintbản thân nó là một đối tượng Python.python print(type(list)) # <class 'type'> print(type(dict)) # <class 'type'> print(type(int)) # <class 'type'> Một instance trỏ tới đối tượng kiểu của nó.python xs = [1, 2, 3] print(type(xs)) # <class 'list'> Ở cấp độ C:```text
xs ---> PyListObject
ob_refcnt
ob_type ----> PyList_Type
ob_size
ob_item
allocated
## 13.2 Tại sao các phần dựng sẵn được triển khai trong C
Các loại tích hợp nằm trên các đường dẫn thực thi Python phổ biến nhất.
Các hoạt động phổ biến bao gồm:```text
integer arithmetic
string hashing
attribute lookup
dictionary lookup
list append
tuple creation
function calls
iteration
exception creation
```Nếu các thao tác này được triển khai như mã Python thông thường, trình thông dịch sẽ phải thực thi nhiều mã byte hơn để thực hiện các thao tác cơ bản của chính nó. CPython tránh điều này bằng cách triển khai các loại lõi trong C.
Ví dụ: từ điển Python được sử dụng cho:```text
module globals
class namespaces
object attributes
keyword arguments
import caches
annotations
many user data structures
```Một từ điển chậm sẽ làm cho toàn bộ trình thông dịch chậm lại.
## 13.3 Mẫu đối tượng tích hợp phổ biến
Hầu hết các triển khai đối tượng tích hợp đều tuân theo hình dạng này:```c
typedef struct {
PyObject_HEAD
/* type-specific fields */
} SomeObject;
```hoặc, đối với các đối tượng có kích thước thay đổi:```c
typedef struct {
PyObject_VAR_HEAD
/* type-specific fields */
} SomeVarObject;
```Đối tượng loại sau đó cung cấp các vị trí:```c
PyTypeObject Some_Type = {
.tp_name = "...",
.tp_basicsize = sizeof(SomeObject),
.tp_dealloc = ...,
.tp_repr = ...,
.tp_as_number = ...,
.tp_as_sequence = ...,
.tp_as_mapping = ...,
.tp_methods = ...,
};
```Mô hình này lặp lại trên CPython.
## 13.4 Họ đối tượng
Các họ đối tượng tích hợp chính là:
| Gia đình | Ví dụ | Vai trò chính |
| -------------- | --------------------------------------------- | -------------------------------- |
| Đối tượng số |`int`, `float`, `complex`, `bool`| Giao thức số học và số |
| Đối tượng văn bản và nhị phân |`str`, `bytes`, `bytearray`, `memoryview`| Văn bản, dữ liệu nhị phân, bộ đệm |
| Đối tượng tuần tự |`list`, `tuple`, `range`| Bộ sưu tập đã đặt hàng |
| Ánh xạ đối tượng |`dict`, `mappingproxy`| Lưu trữ khóa-giá trị |
| Đặt đối tượng |`set`, `frozenset`| Thành viên dựa trên hàm băm |
| Đối tượng có thể gọi được | hàm, phương thức, hàm dựng sẵn | Lời mời |
| Đối tượng thời gian chạy | mô-đun, khung, mã, truy nguyên | Máy thi công |
| Đối tượng mô tả | thuộc tính, getset, thành viên, mô tả phương thức | Hành vi thuộc tính |
| Đối tượng lặp | trình lặp danh sách, trình lặp dict, trình tạo | Lặp lại |
| Đối tượng ngoại lệ |`BaseException`và các lớp con | Lan truyền lỗi |
Mỗi họ sử dụng cùng một mô hình đối tượng nhưng tối ưu hóa cho các hoạt động khác nhau.
## 13.5 Đối tượng số nguyên
Python`int`các giá trị có độ chính xác tùy ý.```python
x = 10**100
print(x)
```CPython lưu trữ số nguyên dưới dạng`PyLongObject`, một đối tượng có kích thước thay đổi. Nó không sử dụng một số nguyên máy cố định cho tất cả các số nguyên Python.
Về mặt khái niệm:```text
PyLongObject
PyVarObject header
ob_size = number of internal digits, with sign encoded
digits[]
```Số nguyên nhỏ sử dụng vài chữ số bên trong. Số nguyên lớn sử dụng nhiều chữ số.
Điều này giải thích tại sao số nguyên Python không tràn như C`long`trong phép tính thông thường.```python
x = 2**1000
print(x * x)
```Chi phí tăng lên với kích thước số nguyên. Các thao tác trên số nguyên nhỏ rất nhanh. Các phép toán trên số nguyên rất lớn đòi hỏi số học có độ chính xác cao.
## 13.6 Đối tượng Boolean`bool`là một lớp con của`int`.
```python
print(isinstance(True, int)) # True
print(True + True) # 2
```Có chính xác hai đối tượng singleton boolean:```python
True
False
```Ở cấp độ C, đây là những đối tượng thuộc sở hữu của thời gian chạy. Mã phải so sánh các giá trị boolean theo giá trị thực ở cấp độ Python chứ không phải bằng cách xây dựng các phiên bản boolean mới.```python
if condition:
...
```Mã C thường trả về các boolean có macro như:```c
Py_RETURN_TRUE;
Py_RETURN_FALSE;
```## 13.7 Đối tượng dấu phẩy động
Python`float`thường được thực hiện dưới dạng C double.
Về mặt khái niệm:```text
PyFloatObject
PyObject header
double value
```Một đối tượng float có kích thước cố định.```python
x = 1.5
y = 2.25
print(x + y)
```Số học nổi tuân theo hành vi dấu phẩy động của nền tảng, nói chung là độ chính xác kép IEEE 754 trên các hệ thống phổ biến.
Một float lưu trữ các số thực nhị phân gần đúng. Nó không đại diện chính xác cho phân số thập phân.```python
print(0.1 + 0.2)
```Kết quả đáng ngạc nhiên đến từ biểu diễn dấu phẩy động nhị phân, không phải từ số học dành riêng cho Python.
## 13.8 Đối tượng phức tạp
Python`complex`lưu trữ hai giá trị dấu phẩy động:```text
PyComplexObject
PyObject header
real double
imag double
```Ví dụ:```python
z = 1.5 + 2.0j
print(z.real)
print(z.imag)
```Số phức tham gia vào các ô số. Chúng hỗ trợ số học nhưng không hỗ trợ so sánh thứ tự như`<`.
```python
1 + 2j < 3 + 4j # TypeError
```## 13.9 Đối tượng chuỗi
Python`str`lưu trữ văn bản Unicode.
Một chuỗi là bất biến.```python
s = "hello"
t = s.upper()
upper()tạo ra một chuỗi khác. Nó không biến đổis.
Việc triển khai Unicode của CPython được tối ưu hóa cho việc lưu trữ nhỏ gọn. Biểu diễn bên trong có thể sử dụng các độ rộng phần tử khác nhau tùy thuộc vào điểm mã lớn nhất trong chuỗi.
Về mặt khái niệm:text PyUnicodeObject object header length hash cache kind compact/ascii flags character data Tối ưu hóa chuỗi quan trọng bao gồm:```text
cached hash value
compact layout
ASCII fast path
interning for selected strings
specialized Unicode operations
## 13,10 Byte và Bytearray`bytes`là dữ liệu nhị phân bất biến.```python
b = b"hello"
bytearraylà dữ liệu nhị phân có thể thay đổi.```python
buf = bytearray(b"hello")
buf[0] = ord("H")
| Loại | Có thể thay đổi | Công dụng chính |
| ----------- | ------: | --------------------- |
|`bytes`| Không | Dữ liệu nhị phân bất biến |
|`bytearray`| Có | Bộ đệm nhị phân có thể thay đổi |
Cả hai đều là các đối tượng giống như chuỗi trên các số nguyên trong phạm vi từ 0 đến 255.```python
b = b"abc"
print(b[0]) # 97
```## 13.11 Danh sách đối tượng
Một danh sách là một chuỗi có thể thay đổi.```python
xs = [1, 2, 3]
xs.append(4)
```Đối tượng danh sách CPython lưu trữ một con trỏ tới một mảng tham chiếu đối tượng được phân bổ riêng.
Về mặt khái niệm:```text
PyListObject
PyVarObject header
ob_size = logical length
ob_item ----> array of PyObject *
allocated = capacity
```Mảng lưu trữ các tham chiếu chứ không phải dữ liệu đối tượng nội tuyến.```text
list
ob_item[0] ---> int object 1
ob_item[1] ---> int object 2
ob_item[2] ---> int object 3
```Danh sách phân bổ quá mức khi phát triển. Điều này làm cho lặp đi lặp lại`append`trung bình có hiệu quả.
## 13.12 Đối tượng Tuple
Một tuple là một chuỗi bất biến.```python
t = (1, 2, 3)
```Một bộ dữ liệu lưu trữ các tham chiếu mục nội tuyến trong phân bổ bộ dữ liệu.
Về mặt khái niệm:```text
PyTupleObject
PyVarObject header
ob_size = length
ob_item[0]
ob_item[1]
ob_item[2]
```Một tuple không thể thay đổi độ dài sau khi tạo. Điều này làm cho việc lưu trữ nội tuyến trở nên thiết thực.
Tính bất biến của bộ dữ liệu đề cập đến các tham chiếu của bộ dữ liệu, không nhất thiết là khả năng biến đổi sâu của các đối tượng được chứa.```python
t = ([],)
t[0].append(1)
print(t) # ([1],)
```Tuple vẫn trỏ đến cùng một danh sách. Danh sách đã thay đổi.
## 13.13 Đối tượng chính tả
Từ điển là một bảng băm ánh xạ các khóa tới các giá trị.```python
d = {"name": "Ada", "age": 36}
```Từ điển được sử dụng xuyên suốt CPython, không chỉ trong mã người dùng.
Họ lưu trữ:```text
module globals
class namespaces
instance attributes
keyword arguments
import caches
```Một tra cứu dict đại khái cần:```text
hash the key
find a matching table slot
compare keys if needed
return associated value
```Thuộc tính quan trọng:```text
average O(1) lookup
insertion order preservation
hash-based key storage
resize when table becomes too full
specialized layouts for object attributes
```Từ điển là một trong những đối tượng nhạy cảm nhất về hiệu suất trong CPython.
## 13.14 Đối tượng Set và Frozenset
Một tập hợp là một bảng băm gồm các khóa không có giá trị.```python
seen = set()
seen.add("x")
```Một Frozenset là bất biến.```python
s = frozenset(["a", "b"])
```Các bộ được tối ưu hóa cho các bài kiểm tra tư cách thành viên:```python
if item in seen:
...
```Cấu trúc bên trong tương tự như dict, nhưng chỉ lưu trữ các phần tử.
Các thao tác thiết lập bao gồm:```text
union
intersection
difference
symmetric difference
subset testing
membership testing
frozensetcó thể băm được nếu tất cả các phần tử đều có thể băm được, vì vậy nó có thể được sử dụng làm khóa từ điển hoặc phần tử tập hợp.
13.15 Đối tượng phạm vi
Arangeđại diện cho một cấp số cộng mà không lưu trữ mọi phần tử.python r = range(0, 1_000_000, 2) Về mặt khái niệm:text range object start stop step length Đối tượng nhỏ gọn ngay cả đối với phạm vi lớn.```python
import sys
print(sys.getsizeof(range(10))) print(sys.getsizeof(range(10**12)))
## 13.16 Đối tượng hàm
Đối tượng hàm Python bao bọc mã thực thi và bối cảnh thời gian chạy.```python
def add(a, b):
return a + b
```Một đối tượng hàm chứa các tham chiếu đến:```text
code object
globals dictionary
defaults
keyword defaults
closure cells
annotations
qualified name
module name
```Về mặt khái niệm:```text
PyFunctionObject
code
globals
defaults
kwdefaults
closure
annotations
name
qualname
```Đối tượng mã chứa mã byte. Đối tượng hàm cung cấp môi trường cần thiết để thực thi mã byte đó.
## 13.17 Đối tượng mã
Một đối tượng mã được biên dịch siêu dữ liệu có thể thực thi được.
Nó chứa:```text
bytecode
constants
names
local variable names
free variables
cell variables
stack size
flags
line table
exception table
filename
function name
```Ví dụ:```python
def f(x):
return x + 1
code = f.__code__
print(code.co_consts)
print(code.co_varnames)
```Các đối tượng mã là bất biến. Chúng có thể được chia sẻ bởi nhiều đối tượng chức năng.
## 13.18 Đối tượng mô-đun
Đối tượng mô-đun đại diện cho một mô-đun được nhập vào.```python
import math
print(math)
```Một mô-đun chủ yếu chứa từ điển không gian tên.
Về mặt khái niệm:```text
module object
name
dict
spec
loader
package
file
```Từ điển mô-đun lưu trữ các biến toàn cục được xác định bởi mô-đun.```python
import math
print(math.__dict__["sqrt"])
```Nhập mô-đun sẽ tạo hoặc truy xuất một đối tượng mô-đun và lưu trữ nó trong`sys.modules`.
## 13.19 Đối tượng lớp và đối tượng
Các lớp là các đối tượng kiểu. Các thể hiện là các đối tượng có con trỏ kiểu trỏ đến lớp.```python
class User:
pass
u = User()
```Về mặt khái niệm:```text
User
type object
attributes and methods
base classes
MRO
u
instance object
ob_type ---> User
instance dictionary or slots
```Các trường hợp thông thường thường lưu trữ các thuộc tính trong từ điển.```python
u.name = "Ada"
```Với`__slots__`, các phiên bản có thể lưu trữ các trường đã chọn theo độ lệch cố định thay vì từ điển.```python
class Point:
__slots__ = ("x", "y")
```Điều này làm giảm bộ nhớ trên mỗi phiên bản và có thể tăng tốc một số kiểu truy cập thuộc tính.
## 13.20 Đối tượng phương thức
Khi một hàm được truy cập thông qua một thể hiện, Python sẽ tạo một đối tượng phương thức bị ràng buộc.```python
class C:
def f(self):
return 1
c = C()
m = c.f
```Phương thức ràng buộc lưu trữ:```text
function
self object
```Về mặt khái niệm:```text
bound method
__func__ ---> C.f
__self__ ---> c
```Đang gọi`m()`vượt qua`c`như đối số đầu tiên.
Đây là hành vi mô tả. Khe mô tả của đối tượng hàm thực hiện liên kết.
## 13.21 Các đối tượng hàm và phương thức tích hợp sẵn
Một số khả năng gọi được được triển khai trực tiếp trong C.
Ví dụ:```python
len
print
dict.get
list.append
```Đây là các đối tượng hàm hoặc phương thức có sẵn. Chúng bao bọc các con trỏ hàm C và siêu dữ liệu.
Chúng nhanh hơn các hàm cấp Python tương đương vì chúng tránh thực thi mã byte Python cho chính thao tác đó.
Một phương pháp tích hợp như`list.append`vẫn nhận các đối tượng Python và tuân theo các quy tắc sở hữu tham chiếu trong nội bộ.
## 13.22 Đối tượng Iterator
Các đối tượng Iterator thực hiện`__iter__`Và`__next__`.
```python
it = iter([1, 2, 3])
print(next(it))
```Một danh sách iterator lưu trữ:```text
reference to list
current index
```Một trình vòng lặp dict lưu trữ:```text
reference to dict
iteration position
version or mutation state
```Các trình tạo cũng là các trình vòng lặp, nhưng chúng phức tạp hơn vì chúng chứa các khung thực thi bị treo.
## 13.23 Đối tượng tạo
Đối tượng trình tạo đại diện cho việc thực thi chức năng bị đình chỉ.```python
def count():
yield 1
yield 2
```Đang gọi`count()`không chạy phần thân hàm ngay lập tức. Nó tạo ra một đối tượng máy phát điện.```python
g = count()
```Trình tạo lưu trữ trạng thái thực thi:```text
code or frame state
instruction position
locals
evaluation stack
exception state
closed/running state
```Mỗi`next(g)`tiếp tục thực hiện cho đến lần tiếp theo`yield`hoặc quay trở lại.
Trình tạo kết nối mô hình đối tượng với mô hình khung trình thông dịch.
## 13.24 Đối tượng khung
Một đối tượng khung đại diện cho một khối mã đang thực thi hoặc bị treo.
Khung chứa:```text
code object
globals
builtins
locals
value stack
instruction pointer
exception state
previous frame link where exposed
```Các khung được tạo cho các lệnh gọi hàm, thực thi mô-đun, thực thi nội dung lớp, trình tạo, coroutine và truy nguyên.
Các đối tượng khung rất quan trọng đối với:```text
debuggers
profilers
trace functions
exceptions
inspect module
generators and coroutines
```Chúng cũng đắt đến mức CPython đã cố gắng tránh hiện thực hóa toàn bộ đối tượng khung hiển thị bằng Python trừ khi cần thiết trong một số đường dẫn.
## 13.25 Đối tượng truy nguyên
Đối tượng truy nguyên ghi lại nơi ngoại lệ được lan truyền.```python
try:
1 / 0
except ZeroDivisionError as exc:
tb = exc.__traceback__
```Một liên kết truy nguyên tới:```text
frame
line number or instruction position
next traceback
```Tracebacks có thể giữ lại khung. Khung có thể giữ lại người dân địa phương. Điều này có nghĩa là các ngoại lệ có thể giữ cho các biểu đồ đối tượng lớn tồn tại.
Đây là kiểu lưu giữ bộ nhớ phổ biến trong các chương trình chạy dài.
## 13.26 Đối tượng ngoại lệ
Ngoại lệ là các đối tượng thông thường có nguồn gốc từ`BaseException`.
```python
try:
raise ValueError("bad")
except ValueError as exc:
print(exc.args)
```Một đối tượng ngoại lệ có thể lưu trữ:```text
args
message data
__cause__
__context__
__traceback__
notes
custom attributes
```Các lớp ngoại lệ là các lớp bình thường, nhưng việc truyền bá ngoại lệ được tích hợp sâu vào trình thông dịch.
## 13.27 Đối tượng mô tả
Bộ mô tả kiểm soát quyền truy cập thuộc tính.
Các loại đối tượng mô tả tích hợp bao gồm:```text
function descriptors
method descriptors
member descriptors
getset descriptors
wrapper descriptors
property objects
classmethod objects
staticmethod objects
```Một bộ mô tả xác định một hoặc nhiều:```python
__get__
__set__
__delete__
```Bộ mô tả thực hiện:```text
methods
properties
slots
C-level members
C-level computed attributes
special method wrappers
```Nếu không có bộ mô tả, mô hình thuộc tính và liên kết phương thức của Python sẽ kém linh hoạt hơn nhiều.
## 13.28 Đối tượng Memoryview
A`memoryview`hiển thị bộ đệm của đối tượng khác mà không cần sao chép.```python
b = bytearray(b"hello")
v = memoryview(b)
```Chế độ xem bộ nhớ giữ cho bộ đệm được xuất tồn tại và cho phép mã đọc hoặc ghi bộ nhớ tùy thuộc vào khả năng thay đổi.
Điều này rất cần thiết cho các hoạt động không sao chép trên các đối tượng giống như byte và các mô-đun mở rộng.
Đối tượng Memoryview tham gia vào các quy tắc về thời gian tồn tại của bộ đệm. Nhà xuất khẩu không được giải phóng hoặc thay đổi kích thước bộ nhớ theo cách làm mất hiệu lực các chế độ xem đang hoạt động.
## 13.29 Đối tượng dạng viên nang
Một viên nang bao bọc một con trỏ C để trao đổi an toàn thông qua API Python.
Các tiện ích mở rộng C sử dụng các viên nang để hiển thị các con trỏ gốc mà không biến chúng thành các đối tượng Python bình thường.
Về mặt khái niệm:```text
capsule
void *pointer
name
destructor
context
```Capsule rất hữu ích cho khả năng tương tác mở rộng C. Chúng cho phép một mô-đun tiện ích mở rộng xuất bản API C mà tiện ích mở rộng khác có thể nhập.
## 13.30 Sự đánh đổi khi triển khai đối tượng
Việc triển khai đối tượng tích hợp cân bằng một số áp lực:
| Áp lực | Hiệu ứng |
| ------------- | ------------------------------------------------- |
| Tốc độ | Đường dẫn C chuyên dụng cho các hoạt động nóng |
| Sử dụng bộ nhớ | Bố cục nhỏ gọn, chia sẻ, thực tập, danh sách miễn phí |
| Khả năng tương thích | Ngữ nghĩa Python ổn định và hành vi API C |
| Khả năng sửa lỗi | Kiểm tra thời gian chạy, xây dựng gỡ lỗi, nội quan |
| Tính di động | Tránh các giả định phá vỡ các nền tảng được hỗ trợ |
| Khả năng mở rộng | Slots, giao thức, hỗ trợ phân lớp |
| An toàn | Đếm tham chiếu, truyền tải GC, xử lý lỗi |
Nhiều chi tiết triển khai CPython xuất phát từ những sự cân bằng này.
Ví dụ: phân bổ quá mức danh sách sẽ cải thiện tốc độ nối thêm nhưng có thể giữ lại thêm bộ nhớ. Thứ tự chèn chính tả tốn bộ nhớ nhưng mang lại hành vi ngôn ngữ hữu ích. Việc đếm tham chiếu cho phép hủy bỏ nhanh chóng nhưng yêu cầu GC chu kỳ và các quy tắc sở hữu API C cẩn thận.
## 13.31 Mô hình tinh thần
Sử dụng mô hình này:```text
built-in type
C struct for instance layout
PyTypeObject for behavior
slots for protocols
methods for public operations
deallocator for owned references
optional GC traversal for cycles
```Khi đọc cách triển khai kiểu tích hợp sẵn, hãy hỏi:```text
What does the object store?
Does it own Python references?
Is it fixed-size or variable-size?
Does it use auxiliary memory?
Does it participate in cyclic GC?
What slots does its type object fill?
What operations are hot paths?
What invariants must always hold?
```## 13.32 Tóm tắt
Các đối tượng tích hợp là các triển khai C chuyên dụng của các giá trị thời gian chạy cốt lõi của Python. Tất cả chúng đều tuân theo cùng một mô hình đối tượng: một tiêu đề chung, một con trỏ kiểu, bộ nhớ dành riêng cho từng loại, quy tắc sở hữu tham chiếu và hành vi được xác định bởi các vị trí loại.
Việc triển khai của chúng được tối ưu hóa vì chúng nằm bên dưới hầu hết mọi chương trình Python. Danh sách, bộ dữ liệu, ký tự, chuỗi, hàm, mô-đun, khung và ngoại lệ không chỉ là tiện ích của thư viện. Chúng là bộ phận làm việc của thông dịch viên.