大家好,我是正在实战各种 AI 项目的程序员晚枫。
函数和类在 C 层面是什么结构?Python 的对象系统是如何工作的?这一讲,彻底搞懂 Python 万物皆对象的本质。
📖 开篇:一切皆对象
在 Python 中,函数、类、甚至类型本身都是对象:
1 2 3 4 5 6 7 8 9 10
| print(type(1)) print(type(int)) print(type(type))
def foo(): pass print(type(foo)) print(foo.__name__) print(foo.__code__)
|
这种「一切皆对象」的设计,让 Python 拥有了强大的元编程能力。
🔧 PyFunctionObject(函数对象)
函数在 C 层面的结构:
1 2 3 4 5 6 7 8 9 10 11 12
| typedef struct { PyObject_HEAD PyObject *func_code; PyObject *func_globals; PyObject *func_defaults; PyObject *func_closure; PyObject *func_doc; PyObject *func_name; PyObject *func_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) print(greet.__defaults__) print(greet.__globals__ is globals())
|
🏛️ PyTypeObject(类型对象)
type 本身也是一个类型,它的类型是 type:
1 2 3
| print(isinstance(int, type)) print(isinstance(str, type)) print(isinstance(list, type))
|
类型对象的核心结构
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; Py_ssize_t tp_basicsize; Py_ssize_t tp_itemsize;
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; traverseproc tp_traverse; inquiry tp_clear; } 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: 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) c.radius = 10
|
描述符的优先级
| 优先级(高到低) | 类型 |
|---|
| 数据描述符 | 实现了 get 和 set/delete |
| 实例属性 | 实例字典中的值 |
| 非数据描述符 | 只实现了 get |
| 类属性 | 类字典中的值 |
元类是「类型的类型」:
1 2 3 4 5 6 7 8 9 10 11
| print(type(1)) print(type(int))
MyClass = type('MyClass', (object,), { 'x': 1, '__init__': lambda self, v: setattr(self, 'x', v) }) obj = MyClass(42) print(obj.x)
|
自定义元类
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
print(MyClass.created_by)
|
💡 本节作业
- 用 inspect 模块查看任意函数的 code 属性
- 手写一个 ReadOnly 描述符,防止属性被修改
- 用 type() 函数(不用 class)创建一个带方法的类
🎯 本讲总结
PyFunctionObject:函数对象的 C 结构体,包含代码、全局命名空间、默认参数等。
PyTypeObject:类型对象的 C 结构体,定义了创建实例的所有行为。
描述符协议:get__、__set__、__delete 控制属性访问。
元类:「类型的类型」,type(name, bases, dict) 是元类的底层实现。
📚 推荐教材
《Python 编程从入门到实践(第 3 版)》 | 《流畅的 Python(第 2 版)》 | 《CPython 设计与实现》
🔗 课程导航
← 上一讲:容器类型实现 | 下一讲:栈帧与调用约定 →
💬 联系我
主营业务:AI 编程培训、企业内训、技术咨询
🎓 AI 编程实战课程
想系统学习 AI 编程?程序员晚枫的 AI 编程实战课 帮你从零上手!