为什么 PyTypeObject 有这么多特定的成员来实现特定的功能
Why PyTypeObject has so many specific members for specific functionality
例如,PyFloat_Type
在tp_as_number
中有很多操作。当这个类型对象被初始化时,所有这些操作将被写入它的 tp_dict
中,并带有插槽。
另一方面,当我编写自定义 class 并在其中包含 __add__
时,它的 tp_dict
将包含 __add__
。这个__add__
函数会在类型对象初始化的时候被写入到带槽类型对象的tp_as_number
中。
我想tp_dict
已经记录了我们需要的所有信息。为什么我们需要 tp_as_number
等其他成员?这只是一个历史问题吗?
因为当 C 级函数正在使用您的类型时,它不会在 tp_dict
中按名称执行查找(慢),而是直接从 tp_as_number
中提取指针(快)。
几个指针取消引用是一个微不足道的成本,不需要引用计数样板等;大多数情况下,成本以个位数周期来衡量,其中 dict
查找的成本要高几个数量级左右。
常见的情况实际上是tp_as_number
,since a + b
will actually use tp_as_number
(or tp_as_sequence
)知道它与tp_dict
中的等效条目同步;如果简单的加法需要 dict
查找,CPython 会比现在慢得多。
例如,PyFloat_Type
在tp_as_number
中有很多操作。当这个类型对象被初始化时,所有这些操作将被写入它的 tp_dict
中,并带有插槽。
另一方面,当我编写自定义 class 并在其中包含 __add__
时,它的 tp_dict
将包含 __add__
。这个__add__
函数会在类型对象初始化的时候被写入到带槽类型对象的tp_as_number
中。
我想tp_dict
已经记录了我们需要的所有信息。为什么我们需要 tp_as_number
等其他成员?这只是一个历史问题吗?
因为当 C 级函数正在使用您的类型时,它不会在 tp_dict
中按名称执行查找(慢),而是直接从 tp_as_number
中提取指针(快)。
几个指针取消引用是一个微不足道的成本,不需要引用计数样板等;大多数情况下,成本以个位数周期来衡量,其中 dict
查找的成本要高几个数量级左右。
常见的情况实际上是tp_as_number
,since a + b
will actually use tp_as_number
(or tp_as_sequence
)知道它与tp_dict
中的等效条目同步;如果简单的加法需要 dict
查找,CPython 会比现在慢得多。