8.PyObjectPyVarObject

PyObjectPyVarObjectlà các bố cục cơ sở đằng sau các đối tượng CPython. Chúng không phải là lớp Python. Chúng là các quy ước cấu trúc cấp C cho phép bộ thực thi xử lý nhiều triển khai đối tượng khác nhau thông qua một kiểu con trỏ chung.

Khi chạy, hầu hết các tham chiếu đối tượng trong CPython được biểu diễn dưới dạng:```c PyObject *


## 8.1 Tiêu đề đối tượng chung

Mt s đơn gin hóa`PyObject`trông như thế này:```c
typedef struct {
    Py_ssize_t ob_refcnt;
    PyTypeObject *ob_type;
} PyObject;
```Định nghĩa thc s s dng macro và các trường ph thuc vào bn dng, đặc bit là trong các bn dng g li, bn dng theo dõi và các phiên bn CPython hin đại. Nhưng ý tưởng thiết yếu là n định:```text
PyObject
    reference count
    type pointer
```S lượng tham chiếu theo dõi quyn s hu.

Con tr kiu cho CPython biết đối tượng hot động như thế nào.

Mi đối tượng CPython bình thường đều bt đầu bng tiêu đề chung này. Do đó, thi gian chy có th nhn được mt`PyObject *`và kim tra loi ca nó mà không biết cu trúc c th đầy đủ ti thi đim biên dch.

## 8.2 Tại sao mọi đối tượng đều bắt đầu theo cùng một cách

Hãy xem xét mã Python này:```python
x = 42
y = "hello"
z = [1, 2, 3]
``` cp độ C, các đối tượng này có b cc khác nhau.```text
PyLongObject
    object header
    integer digit data

PyUnicodeObject
    object header
    string metadata
    character storage

PyListObject
    object header
    length
    allocated capacity
    pointer to item array
```Nhưng mi cái đều bt đầu vi cùng mt tiêu đề:```text
+--------------------+
| ob_refcnt          |
+--------------------+
| ob_type            |
+--------------------+
| type-specific data |
+--------------------+
```Điu này cho phép mã thi gian chy chung hot động vi tt c các đối tượng.

Ví d,`Py_INCREF(obj)`ch cn trường đếm tham chiếu. Không cn biết liu`obj`là mt danh sách, chui, lnh hoc hàm.

Tương t như vy,`Py_TYPE(obj)`ch cn trường con tr kiu.

## 8.3`ob_refcnt`

`ob_refcnt`lưu tr s lượng tham chiếu ca đối tượng.

Tính tham chiếu là cơ chế tn ti ca đối tượng chính ca CPython. Khi mã to, lưu tr, tr v hoc gii phóng các tham chiếu đối tượng, CPython s cp nht s lượng này.

Đơn gin hóa:```c
#define Py_INCREF(op) ((op)->ob_refcnt++)
#define Py_DECREF(op)                         \
    do {                                      \
        if (--(op)->ob_refcnt == 0) {         \
            deallocate_object(op);            \
        }                                     \
    } while (0)
```Vic thc hin thc tế phc tp hơn. Nó x lý các đối tượng bt t, móc g li, truy tìm, xây dng lung t do và chi tiết phân b.

Quy tc khái nim là:```text
new strong reference acquired
    increment reference count

strong reference released
    decrement reference count

reference count reaches zero
    destroy object
```Ví d:```python
x = []
y = x
del x
del y
```Đối tượng danh sách vn tn ti trong khi vn còn ít nht mt tham chiếu mnh.

## 8.4`ob_type`

`ob_type`tr ti đối tượng kiu ca đối tượng.

Đối vi mã Python này:```python
x = []
```đối tượng danh sách`ob_type`ch vào`list`đối tượng gõ.

V mt khái nim:```text
x  --->  PyListObject
            ob_refcnt
            ob_type  ---->  PyList_Type
            ob_size
            ob_item
            allocated
```Đối tượng loi mô t hành vi:```text
object name
object size
base classes
method table
attribute lookup behavior
call behavior
deallocation behavior
number operations
sequence operations
mapping operations
```Đây là cách CPython điu động các hot động.

Khi mã đánh giá:```python
len(x)
```CPython kim tra khe độ dài ca loi.

Khi mã đánh giá:```python
x[0]
```CPython kim tra trình t hoc hành vi ánh x.

Khi mã đánh giá:```python
x + y
```CPython kim tra các khe ni s hoc chui tùy thuc vào loi.

## 8,5`PyObject_HEAD`Các loại tiện ích mở rộng thường không viết các trường theo cách thủ công. Họ sử dụng macro.

Mt đối tượng m rng có kích thước c định thường bt đầu như thế này:```c
typedef struct {
    PyObject_HEAD
    long value;
} CounterObject;

PyObject_HEADmở rộng đến các trường cần thiết cho tiêu đề đối tượng.

Về mặt khái niệm:```c typedef struct { Py_ssize_t ob_refcnt; PyTypeObject *ob_type; long value; } CounterObject;


## 8.6 Đối tượng có kích thước cố định

Mt đối tượng có kích thước c định có cùng kích thước cu trúc C cho mi phiên bn ca loi đó.

Hình dng ví d:```c
typedef struct {
    PyObject_HEAD
    double value;
} FloatLikeObject;
```Mi phiên bn đều có ch cho chính xác mt`double`.

Nhiu đối tượng có kích thước c định  cp độ cu trúc đối tượng:```text
float
module
function
method
cell
weakref
many iterator objects
many descriptor objects
```Đối tượng vn có th tham chiếu đến d liu bên ngoài hoc được phân b riêng. Kích thước c định có nghĩa là bn thân cu trúc đối tượng có kích thước c định, không phi đối tượng logic hoàn chnh không có b lưu tr ph.

Mt đối tượng hàm có kích thước c định dưới dng mt cu trúc, nhưng nó tr đến các đối tượng khác như đối tượng mã ca nó, dict toàn cc, b d liu mc định, b d liu đóng và chú thích.

## 8,7`PyVarObject`Sử dụng các đối tượng có kích thước thay đổi`PyVarObject`.

Mt b cc đơn gin hóa:```c
typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size;
} PyVarObject;
```Nó m rng`PyObject`vi mt trường b sung:```text
ob_size

ob_sizethường lưu trữ kích thước logic của đối tượng.

Ví dụ:text tuple length bytes length integer digit count some internal variable-sized arrays Hình dạng chung:text PyVarObject ob_refcnt ob_type ob_size variable object payload ## 8,8PyObject_VAR_HEADCác loại tiện ích mở rộng có kích thước thay đổi sử dụng:c typedef struct { PyObject_VAR_HEAD PyObject *items[1]; } SmallArrayObject; Về mặt khái niệm:```c typedef struct { Py_ssize_t ob_refcnt; PyTypeObject *ob_type; Py_ssize_t ob_size; PyObject *items[1]; } SmallArrayObject;


Mu này được s dng khi kích thước ca đối tượng được c định sau khi phân b.

Tuples là ví d kinh đin. Độ dài ca b d liu không thay đổi sau khi to, do đó CPython có th phân b mt khi cha tham chiếu mc và tiêu đề đối tượng.

## 8.9 Cái gì`ob_size`Có nghĩa`ob_size`không có nghĩa là “số byte bị đối tượng này chiếm giữ”.

Nó có nghĩa là mt giá tr kích thước c th theo loi.

Đối vi mt tuple, đó là s phn t.

Đối vi byte, đó là s byte.

Đối vi s nguyên dài, nó liên quan đến s ch s cơ s bên trong và có th mã hóa du hiu.

Đối vi loi tùy chnh, ý nghĩa ph thuc vào vic trin khai loi đó.

Điu này rt quan trng.`ob_size`được din gii bng mã dành riêng cho loi đối tượng.```text
same field
different meaning per type
```Đối tượng kiu biết cách din gii các th hin ca chính nó.

## 8.10 Bố cục theo bộ

Mt b d liu là mt ví d đin hình v mt đối tượng có kích thước thay đổi.

V mt khái nim:```c
typedef struct {
    PyObject_VAR_HEAD
    PyObject *ob_item[1];
} PyTupleObject;
```Mt b có độ dài 3 được phân b dưới dng mt đối tượng có khong trng cho ba tham chiếu mc:```text
PyTupleObject
    ob_refcnt
    ob_type  ---> tuple type
    ob_size = 3
    ob_item[0] ---> object A
    ob_item[1] ---> object B
    ob_item[2] ---> object C
```B d liu s hu các tham chiếu đến các mc ca nó. Khi b d liu b hy, nó s gim s lượng tham chiếu ca tng đối tượng được cha.

Tuple không s hu riêng các đối tượng. Nó s hu tài liu tham kho.```python
a = []
t = (a,)
```B d liu lưu tr mt tham chiếu đến danh sách. Tên`a`cũng lưu tr mt tham chiếu đến cùng mt danh sách.

## 8.11 Bố cục danh sách

Mt danh sách cũng có độ dài thay đổi  cp độ Python, nhưng vic trin khai nó khác vi b d liu.

Đối tượng danh sách có cu trúc có kích thước c định tr đến mt mng tham chiếu mc được phân b riêng.

V mt khái nim:```c
typedef struct {
    PyObject_VAR_HEAD
    PyObject **ob_item;
    Py_ssize_t allocated;
} PyListObject;
```Hình dng:```text
PyListObject
    ob_refcnt
    ob_type  ---> list type
    ob_size = current length
    ob_item  ----> separately allocated array
    allocated = current capacity
```Đối vi mt danh sách:```python
xs = [10, 20, 30]
```hình dng b nh xp x:```text
list object
    ob_size = 3
    allocated >= 3
    ob_item ----+
                |
                v
              [ ptr to 10 ][ ptr to 20 ][ ptr to 30 ][ spare capacity... ]
```Điu này cho phép ni thêm hiu qu. Danh sách có th phát trin bng cách phân b li mng mc riêng bit mà không cn di chuyn đối tượng danh sách.

Nhn dng đối tượng vn n định:```python
xs = []
before = id(xs)

xs.append(1)
xs.append(2)
xs.append(3)

after = id(xs)

print(before == after)   # True
```Mng ni b ca danh sách có th di chuyn. Bn thân đối tượng danh sách vn gi nguyên đối tượng đó.

## 8.12 Tại sao đồ vật không chuyển động

CPython thường không di chuyn các vt th sng.

MT`PyObject *`là mt con tr trc tiếp. Nhiu phn ca CPython và nhiu phn m rng ca C có th cha con tr đó.

Nếu CPython di chuyn mt đối tượng trong b nh, nó s phi tìm và cp nht mi con tr ti đối tượng đó. Điu đó s tn kém và không tương thích vi nhiu mã m rng C.

Vì vy CPython s dng mô hình đối tượng không chuyn động.

Hu qu:```text
object identity can be represented by address in CPython
C extensions can hold PyObject * pointers
objects are not compacted by a moving garbage collector
memory fragmentation must be managed differently
```Đây là mt lý do khiến thiết kế b cp phát ca CPython tr nên quan trng.

## 8.13 Truyền giữa các loại đối tượng

Vì mi đối tượng đều bt đầu bng mt tiêu đề chung nên CPython có th truyn các con tr đối tượng c th ti`PyObject *`.

Ví d:```c
PyObject *obj = (PyObject *)some_list;
```Nhưng vic truyn ngược ch an toàn sau khi kim tra kiu.```c
if (PyList_Check(obj)) {
    PyListObject *list = (PyListObject *)obj;
}
```Truyn không an toàn có th làm hng b nh hoc làm hng trình thông dch.

Mã m rng đúng theo mu này:```c
static PyObject *
get_size(PyObject *self, PyObject *arg)
{
    if (!PyList_Check(arg)) {
        PyErr_SetString(PyExc_TypeError, "expected list");
        return NULL;
    }

    Py_ssize_t n = PyList_GET_SIZE(arg);
    return PyLong_FromSsize_t(n);
}
```các`PyList_GET_SIZE`macro gi định đối s ca nó là mt danh sách. Biến th API đã kim tra s an toàn hơn khi loi không chc chn.

## 8.14 API đã được kiểm tra và Macro nhanh

CPython hin th c chc năng đã kim tra và macro nhanh.

Mu đã kim tra:```c
Py_ssize_t n = PyList_Size(obj);
```Dng macro nhanh:```c
Py_ssize_t n = PyList_GET_SIZE(obj);
```Hàm đã kim tra xác thc đối tượng và báo li nếu đầu vào không hp l.

Macro gi định đối tượng đã hp l và có th truy cp trc tiếp vào các trường.

Đánh đổi:

| Mu | An toàn |  Tc độ | Trường hp s dng |
| ---------------- | -----: | -----: | -------------------------------- |
| Đã kim tra chc năng | Cao hơn |  H | Ranh gii công cng, đầu vào không chc chn |
| Macro nhanh |  H | Cao hơn | Mã ni b sau khi xác thc |

Mu này xut hin xuyên sut API C.

## 8.15 Loại Trường Kích thước Đối tượng

Đối tượng loi mô t kích thước cá th.

Các trường quan trng bao gm:```text
tp_basicsize
tp_itemsize

tp_basicsizelà phần cố định của mỗi trường hợp.tp_itemsizelà kích thước của từng mục có kích thước thay đổi đối với các đối tượng có kích thước thay đổi.

Đối với loại có kích thước cố định:text tp_basicsize = sizeof(MyObject) tp_itemsize = 0 Đối với loại có kích thước thay đổi:text tp_basicsize = base header and fixed fields tp_itemsize = size of each trailing item Phân bổ sau đó có thể tính toán:```text total size = tp_basicsize + n * tp_itemsize


## 8.16 Đối tượng mở rộng kích thước cố định tối thiểu

B cc đối tượng có kích thước c định ti thiu:```c
typedef struct {
    PyObject_HEAD
    long value;
} CounterObject;
```Mt bn phác tho đối tượng loi ti thiu:```c
static PyTypeObject CounterType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "example.Counter",
    .tp_basicsize = sizeof(CounterObject),
    .tp_itemsize = 0,
    .tp_flags = Py_TPFLAGS_DEFAULT,
};
```Đim quan trng là cu trúc.```text
CounterObject starts with PyObject header.
CounterType says how large CounterObject is.
CPython allocates memory according to CounterType.
CPython treats the result as PyObject * at generic boundaries.
```## 8.17 Đối tượng mở rộng có kích thước thay đổi tối thiểu

B cc đối tượng có kích thước thay đổi có th trông ging như:```c
typedef struct {
    PyObject_VAR_HEAD
    PyObject *items[1];
} FixedArrayObject;
```Đối tượng loi s s dng kích thước mc khác 0:```c
static PyTypeObject FixedArrayType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "example.FixedArray",
    .tp_basicsize = offsetof(FixedArrayObject, items),
    .tp_itemsize = sizeof(PyObject *),
    .tp_flags = Py_TPFLAGS_DEFAULT,
};
```Phân b s yêu cu độ dài logic c th.

V mt khái nim:```text
allocate FixedArray with n items
    total bytes = tp_basicsize + n * tp_itemsize
    ob_size = n
```B cc này hu ích khi biết s lượng tài liu tham kho được cha ti thi đim to và không thay đổi sau đó.

## 8.18 Macro tiêu đề đối tượng

Các macro ph biến bao gm:```c
Py_REFCNT(obj)
Py_TYPE(obj)
Py_SIZE(obj)
```Ý nghĩa khái nim ca chúng:```text
Py_REFCNT(obj)
    get reference count

Py_TYPE(obj)
    get type pointer

Py_SIZE(obj)
    get variable-size field
```Ví d:```c
PyTypeObject *type = Py_TYPE(obj);
```Và:```c
Py_ssize_t n = Py_SIZE(tuple_obj);
```Mã m rng nên ưu tiên các macro và hàm chính thc hơn là truy cp trường trc tiếp. Điu này làm cho mã tương thích hơn vi nhng thay đổi ca CPython.

## 8.19 Quyền sở hữu và tiêu đề tham chiếu

Tiêu đề đối tượng lưu tr s lượng. Bn thân nó không gii thích quyn s hu.

Quyn s hu là mt quy ước được thc thi bi các quy tc API.

Mt hàm tr v mt tham chiếu mi s chuyn quyn s hu cho người gi:```c
PyObject *x = PyLong_FromLong(42);
/* caller owns x */
Py_DECREF(x);
```Hàm tr v tham chiếu đã mượn không chuyn quyn s hu:```c
PyObject *item = PyList_GetItem(list, 0);
/* borrowed reference, do not DECREF unless INCREF first */
```Tiêu đề đối tượng ging nhau có liên quan đến c hai trường hp. S khác bit là hp đồng ca lnh gi API.

Đây là lý do ti sao vic lp trình m rng CPython li khó khăn. B cc b nh đơn gin nhưng các quy tc s hu đòi hi phi có tính k lut.

## 8.20 Khởi tạo đối tượng

Phân b và khi to là riêng bit.

Đối vi mt đối tượng kiu, vic phân b thường được x lý bi:```text
tp_alloc
```Vic xây dng đối tượng có th bao gm:```text
tp_new
tp_init
``` cp độ Python:```python
obj = MyClass(...)
```đại khái có nghĩa là:```text
call type object
    call tp_new to allocate or return object
    call tp_init to initialize object
    return object
```Đối vi các đối tượng bt biến,`tp_new`thường thc hin hu hết công vic vì giá tr phi được thiết lp trước khi đối tượng được hin th.

Đối vi các đối tượng có th thay đổi,`tp_init`có th đin vào trng thái sau khi phân b.

## 8.21 Phân bổ

Khi s lượng tham chiếu ca mt đối tượng đạt đến 0, CPython s gi b gii phóng theo loi c th.

Đối tượng loi lưu tr điu này trong:```text
tp_dealloc
```Người gii quyết thường thc hin các bước sau:```text
release references owned by the object
free auxiliary buffers
untrack from cyclic GC if needed
free object memory
```Đối vi mt vùng cha, b gii phóng phi gim các tham chiếu đến các đối tượng được cha.

Hình dng ví d:```c
static void
Counter_dealloc(CounterObject *self)
{
    Py_TYPE(self)->tp_free((PyObject *)self);
}
```Đối vi mt thùng cha:```c
static void
Array_dealloc(ArrayObject *self)
{
    for (Py_ssize_t i = 0; i < Py_SIZE(self); i++) {
        Py_XDECREF(self->items[i]);
    }

    Py_TYPE(self)->tp_free((PyObject *)self);
}
```Điu này được đơn gin hóa. Mã thc phi x lý vic theo dõi trình thu gom rác và các bt biến an toàn li.

## 8.22 Tiêu đề thu gom rác

Các đối tượng tham gia thu thp rác theo chu k có th có tiêu đề GC b sung trước phn hin th`PyObject`tiêu đề.

V mt khái nim:```text
GC header
PyObject header
type-specific payload
```các`PyObject *`tr đến tiêu đề đối tượng, không phi tiêu đề GC.```text
memory block start
    GC metadata
    ob_refcnt       <--- PyObject * points here
    ob_type
    payload
```Tiêu đề GC liên kết đối tượng vào các cu trúc b sưu tp.

Ch nhng đối tượng ging như thùng cha có th tham gia vào chu trình thường mi cn tính năng theo dõi này.

Loi tin ích m rng s hu các tham chiếu đến các đối tượng Python khác và có th tham gia vào các chu trình phi trin khai chính xác giao thc GC.

## 8.23 Bản dựng gỡ lỗi

Bn dng g li có th thêm các trường b sung hoc kim tra xung quanh các đối tượng.

Điu này có th bao gm:```text
reference count debugging
allocator padding
forbidden bytes around memory blocks
extra assertions
API misuse detection
```Vì lý do này, mã m rng nên tránh gi định b cc b nh thô chính xác ngoài các macro được ghi li.

Phong cách xu:```c
obj->ob_refcnt++;
```Phong cách tt hơn:```c
Py_INCREF(obj);
```Phong cách xu:```c
obj->ob_type
```Phong cách tt hơn:```c
Py_TYPE(obj)
```Các macro là lp tương thích gia mã m rng và ni b CPython.

## 8.24 Vật thể bất tử

CPython hin đại có khái nim v vt th bt t dành cho nhng vt th có tui th cao được chn. Mt đối tượng bt t s dng mt giá tr đếm tham chiếu đặc bit và tránh vic phá hy s tham chiếu thông thường.

Các ng c viên đin hình bao gm các đối tượng cơ bn ging như singleton hoc thuc s hu thi gian chy.

Đim thiết thc cho độc gi ni b:```text
not every reference count behaves like an ordinary small integer
not every INCREF or DECREF has the same runtime effect
never write code that depends on exact refcount arithmetic unless working inside CPython internals
``` cp độ Python, vic kim tra s tham chiếu đã được trin khai c th.  cp độ C, tác gi tin ích m rng nên s dng API qun lý tham chiếu chính thc.

## 8.25 Tại sao`PyObject`Vấn đề`PyObject`là loại tiền tệ chung của thời gian chạy CPython.

Vòng lp thông dch đẩy và bt`PyObject *`các giá tr.

Cuc gi chc năng vượt qua`PyObject *`lý l.

Ca hàng container`PyObject *`tài liu tham kho.

API tin ích m rng C nhn và tr li`PyObject *`.

Loi khe hot động trên`PyObject *`.

Li được biu th bng các đối tượng ngoi l Python.

Các mô-đun là các đối tượng Python.

Các lp là các đối tượng Python.

Hàm là các đối tượng Python.

Đối tượng mã là đối tượng Python.

Tính đồng nht này là điu làm cho Python tr nên năng động. Thi gian chy có th thao tác các giá tr tùy ý thông qua mt biu din trong khi gi hành vi thông qua các đối tượng kiu.

## 8.26 Mô hình tinh thần hữu ích

Khi đọc mã CPython C, trước tiên hãy gi s hình dng này:```text
PyObject *
    points to object header
        ob_refcnt
        ob_type
    followed by type-specific memory
```Sau đó hi:```text
What concrete type is this object expected to be?
Is it fixed-size or variable-size?
Who owns this reference?
Can this object participate in reference cycles?
What type slot handles this operation?
Does this API return a new reference or borrowed reference?
```Nhng câu hi này ngăn nga s nhm ln sm nht khi đọc ni b CPython.

## 8.27 Tóm tắt`PyObject`là tiêu đề cơ sở cho các đối tượng CPython. Nó cung cấp cho mỗi đối tượng một số tham chiếu và một con trỏ kiểu.`PyVarObject`mở rộng tiêu đề đó bằng trường kích thước được sử dụng bởi các đối tượng có kích thước thay đổi.

S dng các đối tượng có kích thước c định`PyObject_HEAD`.

S dng các đối tượng có kích thước thay đổi`PyObject_VAR_HEAD`.

Tiêu đề đối tượng làm cho h thng đối tượng động ca CPython tr nên kh thi. Nó cho phép mã thi gian chy chung x lý nhiu b cc đối tượng c th thông qua`PyObject *`, trong khi các đối tượng kiu cung cp hành vi cn thiết cho các cuc gi, s hc, lp ch mc, thuc tính, phân b và gi giao thc.