Python对象模型
Python中一切皆对象,所有对象共享统一的底层结构。理解对象模型是深入Python内部机制的基础。
PyObject 结构
每个Python对象在C层面都始于PyObject头:
C
// C层面的定义(简化)
typedef struct _object {
Py_ssize_t ob_refcnt; // 引用计数
PyTypeObject *ob_type; // 类型指针
} PyObject;
// 带变长数据的对象
typedef struct {
PyObject ob_base; // 对象头
Py_ssize_t ob_size; // 元素数量
} PyVarObject;
在Python中观察:
Python
import sys
# 引用计数
x = []
print(sys.getrefcount(x)) # 至少为2(x变量 + getrefcount参数)
# 对象大小
print(sys.getsizeof(x)) # 列表对象本身的大小
print(sys.getsizeof(1)) # 整数对象大小
# 类型对象
print(type(x)) # <class 'list'>
print(type(type(x))) # <class 'type'>
对象头与内存布局
Python
import sys
# 整数对象结构
# PyObject_HEAD (16字节: refcnt + type_ptr)
# ob_digit (变长,存储数值)
n = 12345678901234567890
print(f"整数大小: {sys.getsizeof(n)} 字节")
# 列表对象结构
# PyObject_HEAD (16字节)
# ob_size (8字节,元素数量)
# allocated (8字节,已分配空间)
# items[] (指针数组)
lst = [1, 2, 3]
print(f"列表大小: {sys.getsizeof(lst)} 字节") # 不含元素
# 字符串对象结构
# PyObject_HEAD
# length (8字节)
# hash (-1或缓存值)
# state (1字节)
# UTF-8 length或ASCII标记
# data[]
s = "hello"
print(f"字符串大小: {sys.getsizeof(s)} 字节")
类型对象 PyTypeObject
类型也是对象,其结构定义了对象的行为:
Python
# 类型对象的属性
class MyClass:
"示例类"
attr = 123
def method(self):
pass
# 类型属性
print(MyClass.__name__) # 'MyClass'
print(MyClass.__doc__) # '示例类'
print(MyClass.__dict__) # 命名空间映射
print(MyClass.__bases__) # (<class 'object'>,)
print(MyClass.__mro__) # 方法解析顺序
print(MyClass.__module__) # 定义模块
# 特殊属性
print(int.__itemsize__) # 元素大小(定长类型为0)
print(int.__basicsize__) # 基础大小
print(list.__itemsize__) # 每个元素指针大小
类型槽位(Slots)
类型对象通过槽位定义行为:
Python
# 查看类型的槽位映射
class Counter:
def __init__(self, start=0):
self.value = start
def __add__(self, other):
return Counter(self.value + other)
def __repr__(self):
return f"Counter({self.value})"
def __int__(self):
return self.value
c = Counter(10)
c2 = c + 5
print(c2) # Counter(15)
print(int(c2)) # 15
# 对应的槽位(C层面)
# nb_add -> __add__
# tp_repr -> __repr__
# nb_int -> __int__
常用槽位对应:
| 槽位族 | 特殊方法 | 说明 |
|---|---|---|
| tp_new | __new__ | 对象创建 |
| tp_init | __init__ | 对象初始化 |
| tp_repr | __repr__ | 字符串表示 |
| tp_hash | __hash__ | 哈希值 |
| tp_call | __call__ | 可调用 |
| tp_getattr | __getattr__ | 属性获取 |
| tp_setattr | __setattr__ | 属性设置 |
| tp_iter | __iter__ | 迭代器 |
| tp_iternext | __next__ | 下一个元素 |
| nb_add | __add__ | 加法 |
| sq_length | __len__ | 长度 |
| mp_subscript | __getitem__ | 索引访问 |
type 作为元类
type既是类型,也是元类:
Python
# type 的双重身份
print(type(1)) # <class 'int'>
print(type(int)) # <class 'type'>
print(type(type)) # <class 'type'> - type是自身的实例
# 使用 type 动态创建类
MyClass = type(
'MyClass',
(object,),
{'attr': 123, 'method': lambda self: 'hello'}
)
obj = MyClass()
print(obj.attr) # 123
print(obj.method()) # 'hello'
对象的身份与相等
Python
a = [1, 2, 3]
b = [1, 2, 3]
c = a
# 身份(内存地址)
print(id(a)) # 对象的唯一标识
print(id(b)) # 不同
print(id(c)) # 与a相同
# is 比较身份(比较id)
print(a is b) # False
print(a is c) # True
# == 比较值(调用 __eq__)
print(a == b) # True
# 特殊情况:小整数缓存
print(256 is 256) # True(小整数缓存)
print(257 is 257) # 可能True(编译时常量折叠)
x, y = 257, 257
print(x is y) # 可能False(运行时创建)
不可变对象的可变视图
Python
# 字符串底层是可变缓冲区
import sys
s = "hello"
# 字符串不可变,但可通过内存视图操作底层字节
# bytes 和 bytearray
b = bytes([1, 2, 3]) # 不可变
ba = bytearray([1, 2, 3]) # 可变
ba[0] = 10 # 可修改
# memoryview 提供零拷贝视图
mv = memoryview(ba)
mv[1] = 20
print(ba) # bytearray(b'\n\x14\x03')
要点总结
- PyObject头包含引用计数和类型指针,所有对象共享
- PyVarObject扩展用于变长对象(list、tuple等)
- 类型对象通过槽位定义对象行为
- **
type**既是类型又是元类,是自身的实例 - **
is比较身份(id),==**比较值(__eq__)
📝 发现内容有误?点击此处直接编辑