7. Mô hình đối tượng Python
7. Mô hình đối tượng Python
Mô hình đối tượng Python là nền tảng của CPython. Mọi thứ chạy trong Python cuối cùng đều trở thành một phép toán trên các đối tượng: số nguyên, chuỗi, danh sách, mô-đun, hàm, lớp, ngoại lệ, khung và thậm chí cả mã được biên dịch.
Ở cấp độ ngôn ngữ, Python cho biết mọi đối tượng đều có nhận dạng, loại và giá trị. Nhận dạng đối tượng vẫn cố định sau khi tạo,isso sánh danh tính vàid()trả về một số nguyên đại diện cho danh tính đó. ([Tài liệu Python][1])
CPython triển khai mô hình này với cấu trúc C, tiêu đề đối tượng, số lượng tham chiếu, đối tượng loại và vùng hoạt động.
7.1 Đối tượng, Giá trị và Danh tính
Một đối tượng Python có ba thuộc tính cốt lõi.
| Bất động sản | Ý nghĩa | Ví dụ |
|---|---|---|
| Bản sắc | Nhận dạng ổn định của đối tượng | id(x) |
| Loại | Kiểu thời gian chạy của đối tượng | type(x) |
| Giá trị | Dữ liệu được đại diện bởi đối tượng | 42, "abc", [1, 2] |
Ví dụ:```python x = [1, 2, 3] y = x
print(x is y) # True print(type(x)) # <class 'list'> print(x) # [1, 2, 3]
`x`Và`y`là hai tên được liên kết với cùng một đối tượng. Họ có cùng một danh tính.```python
x.append(4)
print(y) # [1, 2, 3, 4]
```Danh sách đã thay đổi. Sự ràng buộc không tạo ra một bản sao.
Trong CPython, danh tính đối tượng được liên kết chặt chẽ với địa chỉ đối tượng đối với các đối tượng thông thường. Ngôn ngữ chỉ hứa hẹn một danh tính ổn định chứ không phải danh tính đó phải là địa chỉ bộ nhớ.
## 7.2 Tên liên kết với đối tượng
Biến Python là các ràng buộc, không phải hộp lưu trữ.
Mã này:```python
a = 10
b = a
```không sao chép giá trị số nguyên vào`b`. Nó ràng buộc`b`đến cùng một đối tượng được tham chiếu bởi`a`.
Đối với các đối tượng bất biến, điều này thường giống như sao chép giá trị:```python
a = 10
b = a
a = 20
print(b) # 10
```Nhưng đối tượng`10`không thay đổi. Tên`a`đã bật trở lại đối tượng khác.
Đối với các đối tượng có thể thay đổi, sự khác biệt có thể nhìn thấy được:```python
a = []
b = a
a.append("x")
print(b) # ['x']
```Tên`a`và cái tên`b`tham khảo cùng một danh sách. Đột biến thông qua một tham chiếu có thể được nhìn thấy qua tham chiếu kia.
Mô hình tên-đối tượng này là trung tâm của CPython. Các hướng dẫn mã byte chủ yếu tải các tham chiếu đối tượng, lưu trữ các tham chiếu đối tượng, truyền các tham chiếu đối tượng và các thao tác gọi trên các tham chiếu đối tượng.
## 7.3 Mỗi giá trị thời gian chạy là một`PyObject *`Bên trong CPython, các đối tượng thường được xử lý thông qua các con trỏ kiểu`PyObject *`. Tài liệu API C chính thức nêu rõ rằng mọi con trỏ tới đối tượng Python đều có thể được truyền tới`PyObject *`và các bản dựng phát hành thông thường đó lưu trữ số lượng tham chiếu và một con trỏ tới đối tượng loại tương ứng trong cấu trúc đối tượng cơ sở. ([Tài liệu Python][2])
Về mặt khái niệm:```c
typedef struct {
Py_ssize_t ob_refcnt;
PyTypeObject *ob_type;
} PyObject;
```Điều này được đơn giản hóa nhưng nó nắm bắt được mô hình thiết yếu.
Mọi đối tượng đều bắt đầu bằng một tiêu đề được chia sẻ:```text
+--------------------+
| reference count |
+--------------------+
| type pointer |
+--------------------+
| object-specific |
| payload |
+--------------------+
```Đối với một số nguyên, tải trọng lưu trữ các chữ số nguyên.
Đối với một danh sách, tải trọng lưu trữ thông tin kích thước và một con trỏ tới một mảng tham chiếu phần tử.
Đối với một hàm, tải trọng lưu trữ một đối tượng mã, toàn cục, mặc định, ô đóng và siêu dữ liệu liên quan.
Tiêu đề chung cho phép trình thông dịch xử lý tất cả các đối tượng một cách thống nhất ở cấp cao nhất.
## 7.4 Đối tượng có kích thước cố định và kích thước thay đổi
CPython phân biệt các đối tượng có kích thước cố định và các đối tượng có kích thước thay đổi.
Các đối tượng có kích thước cố định sử dụng tiêu đề đối tượng cơ sở.
Các đối tượng có kích thước thay đổi bao gồm một trường kích thước bổ sung. Tài liệu API C mô tả`PyVarObject`như một phần mở rộng của`PyObject`điều đó thêm một`ob_size`trường cho các đối tượng có kích thước thay đổi. ([Tài liệu Python][2])
Về mặt khái niệm:```c
typedef struct {
PyObject ob_base;
Py_ssize_t ob_size;
} PyVarObject;
```Một bộ có kích thước thay đổi vì một bộ có độ dài 2 và một bộ có độ dài 100 cần bộ nhớ khác nhau.
Đối tượng byte có kích thước thay đổi.
Một số nguyên dài cũng có kích thước thay đổi vì CPython lưu trữ các số nguyên có độ chính xác tùy ý bằng cách sử dụng một chuỗi các chữ số.
Hình dạng gần đúng:```text
PyObject
used by many fixed-size objects
PyVarObject
used by objects whose logical size is known at allocation time
```Ví dụ:
| Loại đối tượng | Loại tiêu đề | Lý do |
| ----------- | ----------------------------- | ------------------------------- |
|`float` | `PyObject`| Tải trọng có kích thước cố định |
|`tuple` | `PyVarObject`| Số phần tử thay đổi |
|`bytes` | `PyVarObject`| Số byte khác nhau |
|`int` | `PyVarObject`| Số chữ số nguyên khác nhau |
|`str`| Bố cục biến chuyên dụng | Độ dài chuỗi thay đổi |
## 7.5 Các kiểu đối tượng Xác định hành vi
Kiểu của một đối tượng xác định những hoạt động mà nó hỗ trợ. Mô hình dữ liệu của Python xác định điều này ở cấp độ ngôn ngữ: các đối tượng có loại và loại xác định các hoạt động được hỗ trợ. ([Tài liệu Python][1])
Ở cấp độ CPython, con trỏ kiểu trong tiêu đề đối tượng trỏ tới một`PyTypeObject`.
Về mặt khái niệm:```text
object
ob_refcnt
ob_type --------> type object
name
size
base classes
method table
number slots
sequence slots
mapping slots
call slot
attribute slots
```Khi Python đánh giá:```python
x + y
```CPython không tìm kiếm một vị trí độc lập`add`chức năng. Nó hỏi loại máy móc có liên quan về cách hoạt động của phép cộng đối với các đối tượng đó.
Đối với số nguyên, phép cộng sử dụng mã dành riêng cho số nguyên.
Đối với chuỗi, phép cộng sử dụng nối chuỗi.
Đối với danh sách, phép cộng sẽ tạo ra một danh sách nối.
Đối với các lớp do người dùng định nghĩa, phép cộng có thể gọi`__add__`.
Cú pháp là thống nhất. Việc thực hiện được định hướng theo kiểu.
## 7.6 Kiểu là đối tượng
Một loại bản thân nó là một đối tượng.```python
print(type(42)) # <class 'int'>
print(type(int)) # <class 'type'>
print(type(type)) # <class 'type'>
```Cấu trúc đệ quy này là có chủ ý.`int`là một đối tượng`list`là một đối tượng
Các lớp do người dùng định nghĩa là các đối tượng.
Loại đối tượng loại nhất là`type`.
```python
class User:
pass
print(type(User)) # <class 'type'>
print(type(User())) # <class '__main__.User'>
```Điều này giải thích tại sao các lớp có thể được chỉ định, chuyển, lưu trữ, trang trí và tạo một cách linh hoạt.```python
def make_class():
class Item:
pass
return Item
C = make_class()
obj = C()
```Một câu lệnh lớp tạo ra một đối tượng lớp. Nó liên kết tên lớp với đối tượng đó.
## 7.7 Bố cục đối tượng và Bố cục kiểu
Bố cục của đối tượng CPython phải phù hợp với những gì đối tượng loại của nó mong đợi.
Nguồn CPython nhận xét trong`Include/object.h`lưu ý rằng các đối tượng được truy cập thông qua`PyObject *`và kích thước đối tượng không thay đổi sau khi phân bổ vì việc di chuyển hoặc thay đổi kích thước đối tượng sẽ yêu cầu cập nhật tham chiếu. ([GitHub][3])
Hạn chế đó là quan trọng.
Một danh sách có thể phát triển, nhưng bản thân đối tượng danh sách không mở rộng tại chỗ để chứa tất cả các phần tử một cách trực tiếp. Thay vào đó, nó sở hữu một mảng phần tử riêng biệt có thể phân bổ lại.
Một tuple không thể phát triển. Tham chiếu mục của nó được lưu trữ như một phần của phân bổ bộ dữ liệu.
Về mặt khái niệm:```text
list object
header
current length
allocated capacity
pointer to item array ---> [PyObject*, PyObject*, PyObject*, ...]
tuple object
header
length
inline item references ---> [PyObject*, PyObject*, PyObject*, ...]
```Sự khác biệt này giải thích tại sao việc nối thêm danh sách có thể được khấu hao hiệu quả trong khi kích thước bộ dữ liệu được cố định.
## 7.8 Khả năng thay đổi
Khả năng thay đổi có nghĩa là giá trị của một đối tượng có thể thay đổi trong khi danh tính của nó vẫn giữ nguyên.```python
xs = [1, 2]
before = id(xs)
xs.append(3)
after = id(xs)
print(before == after) # True
```Đối tượng danh sách vẫn giữ nguyên đối tượng. Nội dung của nó đã thay đổi.
Các đối tượng bất biến không hiển thị các hoạt động thay đổi giá trị của chúng tại chỗ.```python
s = "abc"
t = s.upper()
print(s) # abc
print(t) # ABC
```Thao tác chuỗi trả về một đối tượng khác.
Các đối tượng có thể thay đổi và bất biến phổ biến:
| Có thể thay đổi | Bất biến |
| -------------------- | ---------------------------------------------- |
|`list` | `int` |
| `dict` | `float` |
| `set` | `str` |
| `bytearray` | `bytes`|
| hầu hết các trường hợp lớp |`tuple`, nếu các tham chiếu chứa nó được cố định |
Một bộ dữ liệu là bất biến như một vùng chứa, nhưng nó có thể chứa các đối tượng có thể thay đổi:```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.
## 7.9 Ngữ nghĩa tham khảo
Hầu hết các hoạt động thời gian chạy CPython đều di chuyển các tham chiếu đến các đối tượng chứ không phải bản thân các đối tượng.
Các cuộc gọi hàm truyền tham chiếu đối tượng.```python
def add_item(xs):
xs.append(1)
items = []
add_item(items)
print(items) # [1]
```Hàm nhận được một tham chiếu đến cùng một đối tượng danh sách.
Việc đặt lại tên địa phương không ảnh hưởng đến người gọi:```python
def replace(xs):
xs = [1, 2, 3]
items = []
replace(items)
print(items) # []
```Tên`xs`bên trong chức năng đã được phục hồi. Danh sách ban đầu không bị thay đổi.
Sự khác biệt này quan trọng đối với thiết kế API. Thay đổi một đối tượng và đảo ngược một biến cục bộ là các hoạt động khác nhau.
## 7.10 Thuộc tính
Các đối tượng có thể hiển thị các thuộc tính.```python
class User:
pass
u = User()
u.name = "Ada"
print(u.name)
```Đối với các đối tượng thông thường do người dùng định nghĩa, các thuộc tính thể hiện thường được lưu trữ trong một từ điển thể hiện.
Về mặt khái niệm:```text
u
type pointer ---> User
__dict__ -----> {"name": "Ada"}
```Tra cứu thuộc tính phức tạp hơn tra cứu từ điển trực tiếp. CPython phải tính đến:```text
data descriptors
instance dictionary
non-data descriptors
class attributes
base classes
__getattribute__
__getattr__
method binding
```Ví dụ:```python
class User:
species = "human"
u = User()
u.name = "Ada"
print(u.name) # instance attribute
print(u.species) # class attribute
```Nếu thuộc tính đó không có trong phiên bản, CPython sẽ tìm kiếm lớp và các cơ sở của nó.
## 7.11 Các phương thức là mô tả
Một hàm được lưu trữ trên một lớp hoạt động giống như một phương thức khi được truy cập thông qua một thể hiện.```python
class Counter:
def inc(self):
return 1
c = Counter()
print(c.inc)
c.inclà một phương pháp ràng buộc. Nó kết hợp đối tượng hàm với thể hiệnc.
Hành vi này xuất phát từ giao thức mô tả.
Bộ mô tả là một đối tượng xác định một hoặc nhiều:python __get__(self, obj, objtype=None) __set__(self, obj, value) __delete__(self, obj) Chức năng thực hiện__get__, để chúng tự động liên kết khi được truy xuất từ một phiên bản.
Tra cứu khái niệm:```text Counter.inc raw function object
c.inc bound method: function = Counter.inc self = c
## 7.12 Phương pháp đặc biệt và Slots
Cú pháp Python ánh xạ tới các phương thức đặc biệt.
| Cú pháp | Phương pháp đặc biệt |
| --------- | -------------- |
|`x + y` | `__add__` |
| `x[i]` | `__getitem__` |
| `x()` | `__call__` |
| `len(x)` | `__len__` |
| `iter(x)` | `__iter__` |
| `next(x)` | `__next__` |
| `x in y` | `__contains__` |
| `str(x)` | `__str__` |
| `repr(x)` | `__repr__`|
Ở cấp độ CPython, nhiều thao tác trong số này tương ứng với các vị trí trong`PyTypeObject`.
Ví dụ: một loại có thể cung cấp các vị trí số, vị trí trình tự, vị trí ánh xạ và vị trí cuộc gọi.
Điều này có nghĩa là mã Python như:```python
len(obj)
```không chỉ đơn giản là gọi`obj.__len__()`thông qua tra cứu cá thể thông thường. CPython sử dụng máy móc giao thức cấp loại. Điều này làm cho các hoạt động chung nhanh hơn và nhất quán hơn.
## 7.13 Các loại tích hợp là các đối tượng thông thường với các triển khai đặc quyền
Các kiểu tích hợp tham gia vào cùng một mô hình đối tượng, nhưng việc triển khai chúng nằm trong C.```python
print(type([])) # <class 'list'>
print(type({})) # <class 'dict'>
print(type("abc")) # <class 'str'>
```Tài liệu về các loại tích hợp chính thức nhóm các loại tích hợp chính như số, chuỗi, ánh xạ, lớp, phiên bản và ngoại lệ. ([Tài liệu Python][4])
Sự khác biệt giữa`list`và một lớp do người dùng định nghĩa không phải là một lớp là đối tượng còn lớp kia thì không. Cả hai đều là đồ vật. Sự khác biệt là ở chỗ đó`list`có triển khai C với bố cục bên trong cố định và các khe cắm chuyên dụng.
Một đối tượng danh sách Python chứa các chi tiết triển khai như:```text
object header
logical length
allocated capacity
pointer to element storage
```Một lệnh chứa việc triển khai bảng băm.
Một chuỗi chứa bố cục dành riêng cho Unicode và siêu dữ liệu được lưu trong bộ nhớ đệm.
Các bố cục bên trong này được tối ưu hóa cho hoạt động thời gian chạy của CPython.
## 7.14 Lớp và phiên bản
Một lớp xác định hành vi được chia sẻ bởi các thể hiện của nó.```python
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(10, 20)
```Khi chạy:```text
Point
class object
type: type
attributes:
__init__
...
p
instance object
type: Point
attributes:
x = 10
y = 20
```Gọi lớp gọi máy móc xây dựng:```text
Point(10, 20)
call type object
allocate instance through __new__
initialize instance through __init__
return instance
```Đây là lý do tại sao việc xây dựng có thể được tùy chỉnh:```python
class OnlyOne:
def __new__(cls):
print("allocate")
return super().__new__(cls)
def __init__(self):
print("initialize")
__new__tạo hoặc trả về một đối tượng.__init__khởi tạo nó.
7.15 Kế thừa và giải quyết phương pháp
Python hỗ trợ kế thừa thông qua các lớp.```python class Animal: def speak(self): return "?"
class Dog(Animal):
def speak(self):
return "woof"
Khi phân giải một thuộc tính trên một thể hiện, CPython tìm kiếm theo thứ tự phân giải phương thức lớp, thường được gọi là MRO.python
print(Dog.mro)
Đối với thừa kế đơn:text
Dog
Animal
object
Đối với đa kế thừa, Python sử dụng tuyến tính hóa C3.python
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
print(D.mro)
## 7.16 Thứ tự tra cứu thuộc tính
Đối với một biểu thức bình thường:```python
obj.name
```CPython thực hiện tra cứu có cấu trúc.
Thứ tự đơn giản:```text
1. Look for data descriptors on the type or its bases.
2. Look in the instance dictionary.
3. Look for non-data descriptors or other class attributes.
4. If still missing, call __getattr__ if defined.
5. Otherwise raise AttributeError.
```Bộ mô tả dữ liệu xác định`__set__`hoặc`__delete__`.
Một bộ mô tả phi dữ liệu chỉ xác định`__get__`.
Điều này giải thích tại sao`property`có thể ghi đè một mục từ điển mẫu:```python
class User:
@property
def name(self):
return "computed"
u = User()
print(u.name)
```Thuộc tính là một bộ mô tả dữ liệu. Nó chiến thắng việc lưu trữ phiên bản thông thường.
## 7.17 Tạo đối tượng
Việc tạo đối tượng thường có hai giai đoạn.```text
allocation
reserve memory for the object
initialization
set the initial object state
```Ở cấp độ Python:```python
obj = cls.__new__(cls)
cls.__init__(obj)
```Trong mã thông thường, việc gọi lớp thực hiện cả hai bước.
Ở cấp độ C, đối tượng loại kiểm soát việc phân bổ và khởi tạo thông qua các vị trí như:```text
tp_new
tp_init
tp_alloc
tp_dealloc
```Sự tách biệt này quan trọng vì các đối tượng bất biến cần giá trị của chúng trong quá trình tạo.
Ví dụ: một tuple hoặc int không thể được tạo trống và sau đó tự do biến đổi thành giá trị cuối cùng của nó thông qua các hoạt động công khai. Giá trị cuối cùng của chúng được thiết lập trong quá trình phân bổ hoặc xây dựng.
## 7.18 Phá hủy đối tượng
Việc phá hủy đối tượng trong CPython chủ yếu dựa vào số lượng tham chiếu.
Khi số lượng tham chiếu của một đối tượng đạt đến 0, CPython sẽ gọi hàm phân bổ của nó.
Về mặt khái niệm:```text
Py_DECREF(obj)
decrement reference count
if reference count == 0:
call type-specific deallocator
```Bộ cấp phát giải phóng các tham chiếu thuộc sở hữu của đối tượng, giải phóng bộ nhớ phụ và trả về bộ nhớ của đối tượng cho bộ cấp phát.
Đối với các container, việc phân bổ có thể xếp tầng:```python
xs = [[1], [2], [3]]
del xs
```Xóa danh sách bên ngoài sẽ giảm tham chiếu đến danh sách bên trong. Nếu những danh sách bên trong đó không có tài liệu tham khảo nào khác thì chúng cũng bị hủy.
Các chu kỳ yêu cầu thu thập rác theo chu kỳ, vì chỉ số lượng tham chiếu không thể lấy lại các đối tượng giúp nhau tồn tại.
## 7.19 Bình đẳng và bản sắc
Bản sắc và sự bình đẳng là khác nhau.```python
a = [1, 2]
b = [1, 2]
print(a == b) # True
print(a is b) # False
==hỏi xem các đối tượng có so sánh bằng nhau không.ishỏi xem hai tham chiếu có trỏ đến cùng một đối tượng hay không.
Ở cấp độ CPython:```text is compare object pointers
==
dispatch rich comparison through type machinery
Các lớp tùy chỉnh có thể định nghĩa sự bình đẳng:python
class Point:
def init(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return (
isinstance(other, Point)
and self.x == other.x
and self.y == other.y
)
## 7.20 Băm
Băm hỗ trợ các khóa từ điển và tập hợp các phần tử.
Một đối tượng được sử dụng làm khóa chính tả phải có hàm băm ổn định khi nó vẫn còn trong từ điển.```python
d = {}
d["name"] = "Ada"
```Các chuỗi có thể băm được vì chúng không thay đổi được.
Danh sách không thể băm được vì nội dung của chúng có thể thay đổi:```python
hash("abc") # works
hash((1, 2)) # works
hash([1, 2]) # TypeError
```Một lớp tùy chỉnh có thể định nghĩa:```python
__hash__
__eq__
```Quy tắc này rất thực tế: nếu đẳng thức có thể thay đổi thì bảng băm có thể bị hỏng. Các đối tượng có thể thay đổi thường nên tránh băm dựa trên giá trị.
## 7.21 Tài liệu tham khảo về cửa hàng container
Vùng chứa Python lưu trữ các tham chiếu đến các đối tượng.```python
xs = [object(), object(), object()]
```Danh sách lưu trữ các tham chiếu đến ba đối tượng. Nó không nội tuyến dữ liệu đối tượng hoàn chỉnh của họ.
Về mặt khái niệm:```text
list
items[0] ---> object A
items[1] ---> object B
items[2] ---> object C
```Điều này giải thích hành vi sao chép nông:```python
a = [[1], [2]]
b = a.copy()
b[0].append(99)
print(a) # [[1, 99], [2]]
```Danh sách bên ngoài đã được sao chép. Các đối tượng danh sách bên trong đã được chia sẻ.
Một bản sao sâu sao chép đệ quy các đối tượng chứa:```python
import copy
a = [[1], [2]]
b = copy.deepcopy(a)
```## 7.22 Giao thức đối tượng
Python dựa vào các giao thức hơn là các giao diện rõ ràng.
Một đối tượng tham gia vào một giao thức bằng cách thực hiện các phương thức phù hợp.
Giao thức lặp:```python
class Count:
def __init__(self, stop):
self.current = 0
self.stop = stop
def __iter__(self):
return self
def __next__(self):
if self.current >= self.stop:
raise StopIteration
value = self.current
self.current += 1
return value
```Giao thức vùng chứa:```python
class Bag:
def __init__(self):
self.items = []
def __contains__(self, item):
return item in self.items
```Giao thức quản lý bối cảnh:```python
class Resource:
def __enter__(self):
return self
def __exit__(self, exc_type, exc, tb):
return False
```Các giao thức này cho phép các đối tượng do người dùng định nghĩa hoạt động với cú pháp như:```python
for x in obj:
...
with obj:
...
if x in obj:
...
```Mô hình đối tượng là cầu nối giữa cú pháp và hành vi.
## 7.23 Một mô hình nội bộ hữu ích
Một biểu thức Python như:```python
result = obj.method(x) + y
```có thể được đọc dưới dạng các hoạt động của mô hình đối tượng:```text
load obj
look up attribute "method"
bind method to obj if descriptor rules apply
load x
call bound method
load y
perform binary addition through type slots
bind result name to returned object
```Mỗi bước di chuyển hoặc tạo tham chiếu đối tượng.
Mọi hoạt động đều được trung gian bởi thông tin loại.
Mỗi kết quả là một tham chiếu đối tượng khác.
## 7.24 Phác thảo cấp độ C tối thiểu
Loại tiện ích mở rộng được đơn giản hóa bắt đầu bằng tiêu đề đối tượng CPython.```c
typedef struct {
PyObject_HEAD
long value;
} CounterObject;
```các`PyObject_HEAD`macro cung cấp tiêu đề đối tượng tiêu chuẩn cần thiết cho CPython để coi bộ nhớ này là đối tượng Python. Đối tượng loại sau đó mô tả cách đối tượng này hoạt động.```c
static PyTypeObject CounterType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "example.Counter",
.tp_basicsize = sizeof(CounterObject),
.tp_flags = Py_TPFLAGS_DEFAULT,
};
```Các loại tiện ích mở rộng thực sự cần nhiều trường, khởi tạo, phương thức, xử lý lỗi, thiết lập mô-đun và quyền sở hữu tham chiếu hơn. Nhưng hình dạng thì giống nhau:```text
instance memory starts with object header
type object describes behavior
runtime manipulates the object through PyObject *
```##7.25 Tóm tắt
Mô hình đối tượng Python cho biết mọi giá trị đều có nhận dạng, loại và giá trị. CPython hiện thực hóa mô hình này bằng`PyObject *`con trỏ, tiêu đề đối tượng, số lượng tham chiếu, đối tượng loại và vị trí hoạt động.
Một cái tên gắn liền với một đối tượng. Một container lưu trữ các tham chiếu đến các đối tượng. Một loại xác định hành vi. Một lớp là một đối tượng. Một instance trỏ đến lớp của nó. Cú pháp như bổ sung, gọi, lập chỉ mục, lặp và truy cập thuộc tính được thực hiện thông qua máy móc giao thức hướng kiểu.
Mô hình này là cơ sở cho phần còn lại của CPython: quản lý bộ nhớ, thực thi mã byte, tra cứu thuộc tính, gọi hàm, lớp, bộ mô tả, mô-đun mở rộng và API C.