微信号:programmer_club

介绍:程序员第一自媒体,与你探讨码农人生路上遇到的各类泛技术话题,定期为你推荐码农人生思考、感悟以及启迪!

Python 源码阅读:类型

2017-09-29 20:30 程序员之家

这篇主要涉及Python对象的类型机制


有点绕, 一定要思维清晰的时候再看哦:)


一个例子


>>> a = 1

>>> a

1

 

>>> type(a)

 

#等价的两个

>>> type(type(a))

 

>>> type(int)

 

#还是等价的两个

>>> type(type(type(a)))

 

>>> type(type(int))


我们反向推导一个int对象是怎么生成的.




1. 首先, 定义一种类型叫PyTypeObject


代码位置 Include/object.h


定义


typedef struct _typeobject {

 

  /* MARK: base, 注意, 是个变长对象*/

  PyObject_VAR_HEAD

  const char *tp_name; /* For printing, in format "." */ //类型名

  Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */ // 创建该类型对象时分配的内存空间大小

 

  // 一堆方法定义, 函数和指针

  /* Methods to implement standard operations */

  printfunc tp_print;

  hashfunc tp_hash;

 

  /* Method suites for standard classes */

  PyNumberMethods *tp_as_number;   // 数值对象操作

  PySequenceMethods *tp_as_sequence; // 序列对象操作

  PyMappingMethods *tp_as_mapping; // 字典对象操作

 

  // 一堆属性定义

  ....

 

} PyTypeObject;


说明


1. tp_name

类型名, 这里是"type"

 

2. PyVarObject_HEAD_INIT(&PyType_Type, 0)

PyVarObject_HEAD_INIT, 这个方法在 Include/object.h,

等价于

        ob_refcnt = 1

        *ob_type = &PyType_Type

        ob_size = 0

 

, PyType_Type的类型是其本身!1. tp_name

类型名, 这里是"type"

 

2. PyVarObject_HEAD_INIT(&PyType_Type, 0)

PyVarObject_HEAD_INIT, 这个方法在 Include/object.h,

等价于

        ob_refcnt = 1

        *ob_type = &PyType_Type

        ob_size = 0

 

, PyType_Type的类型是其本身!


所有Type都是PyTypeObject的”实例”: PyType_Type/PyInt_Type




2. 然后, 用PyTypeObject初始化得到一个对象PyType_Type


代码位置 Objects/typeobject.c


定义


PyTypeObject PyType_Type = {

  PyVarObject_HEAD_INIT(&PyType_Type, 0)

  "type",                                     /* tp_name */

  sizeof(PyHeapTypeObject),                   /* tp_basicsize */

  sizeof(PyMemberDef),                        /* tp_itemsize */

  (destructor)type_dealloc,                   /* tp_dealloc */

 

  // type对象的方法和属性初始化值

  .....

 

};


说明


1. tp_name

类型名, 这里是"type"

 

2. PyVarObject_HEAD_INIT(&PyType_Type, 0)

PyVarObject_HEAD_INIT, 这个方法在 Include/object.h,

等价于

        ob_refcnt = 1

        *ob_type = &PyType_Type

        ob_size = 0

 

, PyType_Type的类型是其本身!1. tp_name

类型名, 这里是"type"

 

2. PyVarObject_HEAD_INIT(&PyType_Type, 0)

PyVarObject_HEAD_INIT, 这个方法在 Include/object.h,

等价于

        ob_refcnt = 1

        *ob_type = &PyType_Type

        ob_size = 0

 

, PyType_Type的类型是其本身!1. tp_name

类型名, 这里是"type"

 

2. PyVarObject_HEAD_INIT(&PyType_Type, 0)

PyVarObject_HEAD_INIT, 这个方法在 Include/object.h,

等价于

        ob_refcnt = 1

        *ob_type = &PyType_Type

        ob_size = 0

 

, PyType_Type的类型是其本身!


结构


第一张图, 箭头表示实例化(google doc用不是很熟找不到对应类型的箭头)


第二张图, 箭头表示指向


使用

# 1. int 的 类型 是`type`

>>> type(int)

 

# 2. type 的类型 还是`type`, 对应上面说明第二点

>>> type(type(int))


注意: 无论任何时候, ob_type指向的是 PyTypeObject的实例: PyType_Type/PyInt_Type…




3. 再然后, 定义具体的类型, 这里以PyInt_Type为例子


代码位置 Objects/intobject.c


定义


PyTypeObject PyInt_Type = {

  PyVarObject_HEAD_INIT(&PyType_Type, 0)

  "int",

  sizeof(PyIntObject),

  0,

 

  // int类型的相关方法和属性值

  ....

 

  (hashfunc)int_hash,                         /* tp_hash */

 

};


说明


1. "int"

PyInt_Type的类型名是int

 

2.PyVarObject_HEAD_INIT(&PyType_Type, 0)

PyInt_Type的

 

    *ob_type = &PyType_Type


结构



使用


>>> type(1)

<type 'int'>

 

>>> type(type(1))

<type 'type'>




4. 最后, 生成一个整数对象int


代码位置 Include/intobject.h


定义


typedef struct {

    PyObject_HEAD

    long ob_ival;

} PyIntObject;


结构



1. PyIntObject为整数类型

 

2. 声明一个整数后得到整数对象

 

3. 对象ob_type指向PyInt_type对象




到这里, 总结下


1. 一切都是对象

 

2. PyType_Type / PyInt_Type / PyString_Type ....

这些是`类型对象`, 可以认为是同级, 都是PyTypeObject这种`类型`的实例!

 

3. 虽然是同级,

但是其他PyXXX_Type, 其类型指向 PyType_Type

PyType_Type 的类型指向自己, 它是所有类型的`类型`

 

4. PyTypeObject 是一个变长对象

 

5. 每个object, 例如PyIntObject都属于一种`类型`

object初始化时进行关联




多态是如何实现的?


对象的多态, 例如hash


>>> hash(1)

1

>>> hash("abc")

1453079729188098211


从上面数据结构可以看到, 方法及属性, 在不同Type实例化时就确定了


PyTypeObject PyInt_Type = {

    ...

    (hashfunc)int_hash,                         /* tp_hash */

    ...

}

 

PyTypeObject PyString_Type = {

    ...

    (hashfunc)string_hash,                      /* tp_hash */

    ...

}


Python内部传递的是泛型指针PyObject *, 函数调用时, 找到其类型* ob_type, 然后调用


object -> ob_type -> tp_hash


即: 大量函数指针决定了该类型的具体行为


来源:wklken


编辑 | 码哥

图片源于网络,版权归原作者所有

 
程序员之家 更多文章 性奴、割器官,每年至少250万人旅游失踪?他们都去了哪? 程序员爱吃树莓派?好吃么? 6年来微信首次换图,换中国的! 顶级程序员有一个共同点,那就是...... 马云吃泡面咸菜照片引500万次围观 网友:辛苦了
猜您喜欢 [ISUX译]iOS 9人机界面指南(四):UI元素(上) - 腾讯ISUX 北漂还是回家发展? Facebook 将向所有员工提供 4 个月带薪陪产假 搜狗输入法首届表情大奖赛