大家好,我是正在实战各种 AI 项目的程序员晚枫。

函数和类在 C 层面是什么结构?Python 的对象系统是如何工作的?这一讲,彻底搞懂 Python 万物皆对象的本质。


📖 开篇:一切皆对象

在 Python 中,函数、类、甚至类型本身都是对象:

1
2
3
4
5
6
7
8
9
10
print(type(1))           # <class 'int'>
print(type(int)) # <class 'type'>
print(type(type)) # <class 'type'> type 是自己的类型!

# 函数也是对象
def foo():
pass
print(type(foo)) # <class 'function'>
print(foo.__name__) # 'foo'
print(foo.__code__) # 代码对象

这种「一切皆对象」的设计,让 Python 拥有了强大的元编程能力。


🔧 PyFunctionObject(函数对象)

函数在 C 层面的结构:

1
2
3
4
5
6
7
8
9
10
11
12
// Include/funcobject.h
typedef struct {
PyObject_HEAD
PyObject *func_code; // 代码对象(PyCodeObject)
PyObject *func_globals; // 全局命名空间(字典)
PyObject *func_defaults; // 默认参数(元组)
PyObject *func_closure; // 闭包变量(元组)
PyObject *func_doc; // 文档字符串
PyObject *func_name; // 函数名
PyObject *func_dict; // 实例字典(__dict__)
PyObject *func_weakreflist; // 弱引用列表
} PyFunctionObject;

验证函数对象

1
2
3
4
5
6
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"

print(greet.__code__.co_varnames) # ('name', 'greeting') 局部变量名
print(greet.__defaults__) # ('Hello',) 默认参数值
print(greet.__globals__ is globals())# True 全局命名空间

🏛️ PyTypeObject(类型对象)

type 本身也是一个类型,它的类型是 type:

1
2
3
print(isinstance(int, type))   # True
print(isinstance(str, type)) # True
print(isinstance(list, type)) # True

类型对象的核心结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; // 类型名称,如 "int"
Py_ssize_t tp_basicsize; // 实例的基础大小
Py_ssize_t tp_itemsize; // 变长对象的 item 大小

// 核心方法
destructor tp_dealloc; // 销毁函数
getattrfunc tp_getattr; // 属性获取
setattrfunc tp_setattr; // 属性设置

// 方法族(每种操作一组函数指针)
PyNumberMethods *tp_as_number; // 数值运算
PySequenceMethods *tp_as_sequence; // 序列操作
PyMappingMethods *tp_as_mapping; // 映射操作

// 其他功能
hashfunc tp_hash; // 哈希函数
reprfunc tp_repr; // repr() 返回的字符串
traverseproc tp_traverse; // GC 遍历
inquiry tp_clear; // GC 清除
} PyTypeObject;

🔄 描述符协议(Descriptor)

描述符让属性访问可以被拦截:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class ReadOnly:
# 手写一个 property 描述符
def __init__(self, fget):
self.fget = fget

def __get__(self, obj, owner):
if obj is None:
return self
return self.fget(obj)

def __set__(self, obj, value):
raise AttributeError("read-only")

class Circle:
def __init__(self, radius):
self._radius = radius

@ReadOnly
def radius(self):
return self._radius

c = Circle(5)
print(c.radius) # 5
c.radius = 10 # AttributeError: read-only

描述符的优先级

优先级(高到低)类型
数据描述符实现了 getset/delete
实例属性实例字典中的值
非数据描述符只实现了 get
类属性类字典中的值

⚡ 元类(Metaclass)

元类是「类型的类型」:

1
2
3
4
5
6
7
8
9
10
11
# type() 既可以创建对象,也可以创建类
print(type(1)) # <class 'int'>
print(type(int)) # <class 'type'>

# 用 type() 创建类
MyClass = type('MyClass', (object,), {
'x': 1,
'__init__': lambda self, v: setattr(self, 'x', v)
})
obj = MyClass(42)
print(obj.x) # 42

自定义元类

1
2
3
4
5
6
7
8
9
10
11
class Meta(type):
def __new__(cls, name, bases, namespace):
print(f"Creating class: {name}")
namespace['created_by'] = 'Meta'
return super().__new__(cls, name, bases, namespace)

class MyClass(metaclass=Meta):
pass

# 输出: Creating class: MyClass
print(MyClass.created_by) # Meta

💡 本节作业

  1. 用 inspect 模块查看任意函数的 code 属性
  2. 手写一个 ReadOnly 描述符,防止属性被修改
  3. 用 type() 函数(不用 class)创建一个带方法的类

🎯 本讲总结

PyFunctionObject:函数对象的 C 结构体,包含代码、全局命名空间、默认参数等。

PyTypeObject:类型对象的 C 结构体,定义了创建实例的所有行为。

描述符协议get__、__set__、__delete 控制属性访问。

元类:「类型的类型」,type(name, bases, dict) 是元类的底层实现。


📚 推荐教材

《Python 编程从入门到实践(第 3 版)》 | 《流畅的 Python(第 2 版)》 | 《CPython 设计与实现》


🔗 课程导航

上一讲:容器类型实现 | 下一讲:栈帧与调用约定


💬 联系我

平台账号/链接
微信扫码加好友
B 站Python 自动化办公社区

主营业务:AI 编程培训、企业内训、技术咨询

🎓 AI 编程实战课程

想系统学习 AI 编程?程序员晚枫的 AI 编程实战课 帮你从零上手!