Python源码学习(一)

python基础

Python中一切都是对象,一个实例是一个对象,生成实例的类也是对象,描述类的元类也是对象。
TODO:类的继承链的图片
这张图里面,可以看出来,无论是内置类型int还是自定义类型dog,他们的基类都是object。而且描述他们类型的元类型都是type,object是所有类型的基类,本质上也是一个类,所以他的类型也是type。Type是所有类型的类型,本质上也是一种类型,所以它继承自object,类型是它自己。总体来看,所有类型的基类都收敛于object,所有类型的类型都是type。

PyObject

Python中的变量只是一个跟对象关联的名字,保存的其实是指向实际对象的指针,变量的赋值操作也就是一个拷贝指针的操作。
Python中对象可以分为可变对象和不可变对象;顾名思义,区别就是创建后对象的值能不能修改。也可分为定长对象和变长对象:区别就是对象大小能不能改变

typedef struct _object {
	_PyObject_HEAD_EXTRA
	Py_ssie_t ob_refcnt;    //引用计数
	PyTypeObject *ob_type;	//类型指针
} PyObject;

PyObject结构体是所有对象共用的部分,这其中包含一个引用计数,记录被引用次数,一个类型指针,指向对象的类型对象,比如刚才的dog实例的类型对象,就是dog类。这是一个最基础的对象结构。

PyVarObject

下面这个是变长对象,跟PyObject相比,多出一个ob_size字段,用来记录元素个数。变长比如string,list。

typedef struct {
	PyObject ob_base;
	Py_ssize_t ob_size;
} PyVarObject;

PyTypeObject

typedef struct _typeobject {
	PyObject_VAR_HEAD
	const char *tp_name;	//类型名称
	Py_ssize_t tp_basicsize, tp_itemsize;	//创建对象所需的内存信息

	// 该类型支持的操作信息
	destructor tp_dealloc;
	printfunc tp_print;

	getattrfunc tp_getattr;
	setattrfunc tp_setattr;

	//...

	struct _typeobject *tp_base; 	//类型的继承信息

	//...
} PyTypeObject;

在创建对象的时候,不同的对象它肯定需要不同的内存大小,PyObject只提供了所有对象共有的信息,其他的一些元信息,都放在PyTypeObject这个结构体中,也就是前面说的类型对象,它来描述这个对象是什么类型,有什么继承关系,支持什么操作,需要多少内存这些信息。

Object 和 Type_Type

刚才我们还介绍了两个概念,一个是所有类的基类Object,还有一个是描述类型的类型,被称为元类型type。

PyTypeObject PyType_Type = {
	PyVarObject_HEAD_INIT(&PyType_Type, 0)
	"type",
	sizeof(PyHeapTypeObject),
	sizeof(PyMemberDef),
	(destructor)type_dealloc,

	//...
	(reprfunc)type_repr,
	(ternaryfunc)type_call,

	//...
};
PyTypeObject PyBaseObject_Type = {
	PyVarObject_HEAD_INIT(&PyType_Type, 0)
	"object",
	sizeof(PyObject),
	0,
	object_dealloc,

	//...
	object_repr,
};

Object背后的实体就是PyBaseObject_type,跟前面的类型对象对比,他没有设置tp_base字段记录继承信息,因为它要作为继承链的终点,防止进入死循环。

小结

在这里插入图片描述

到这里我们基本可以弄清楚python对象体系的关系。变量名指向一个实例对象,这个对象包含基本的pyobject,ob_type指向它的类型对象PyFloat_Object,这个类型对象的type字段中,指向的是类型的类型PyType_type对象,tp_base中记录着继承信息,基类是pyBaseObject_type,另外PyBaseObject_type是元类型的基类,PyType_Tpye是object的类型。

生命周期

接下来我们再了解一下对象的生命周期。

static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
	PyObject *obj;

	//...
	obj = type->tp_new(type, args, kwds);
	obj = _Py_CheckFunctionResult((PyObject*)type, obj, NULL);
	if (obj == NULL)
		return NULL;

	//...
	type = Py_TYPE(obj);
	if (type->tp_init != NULL) {
		int res = type->tp_init(obj, args, kwds);
		if (res < 0){
			assert(PyErr_Occurred());
			Py_DECREF(obj);
			obj = NULL;
		}
		else {
			assert(!PyErr_Occurred());
		}
	}
	return obj;
}

我们还记得类型对象中的tp_call字段,当对象被创建的时候会通过类型对象调用tp_call方法,这里先调用了tp_new申请内存,然后如果它有init的话会调用tp_init对对象进行初始化。这是两个比较关键的操作。

#define PyINCREF(op) (
	_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA
	((PyObject*)(op))->ob_refcnt++)

#define Py_DECREF(op)
	do{
		if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA
			--((PyObject*)(op))->ob_refcnt != 0)
			_Py_CHECK_PRECNT(op)
		else
			_Py_Dealloc((PyObject *)(op));
	} while (0)

对象的销毁是通过PyObject对象中的引用计数来判断的。刚才对象创建调用完tp_new方法之后,会执行增加引用计数的宏,然后init失败之后减少引用计数。这两个宏分别是Py_INCREF和Py_DECREF,可以看到都在操作pyObject中的记录引用次数的这个字段,在指针为零时还会会销毁或者回收对象。
TODO:插入图片

不同的对象肯定有不一样的行为,通过行为可以把对象分成不同的类别。数值型的对象会有加减乘除等操作,序列型的对象有下标操作,关联型对象会产生约束。Python为每一个类别都定义了一个标准操作集。数值型对象比如int,float;序列型对象str,bytes,tuple,list;关联型对象dict
在类型对象PyTypeObject中,可以看到三个操作集的定义:type_as_number,type_as_sequence,type_as_mapping

typedef struct _typeobject
{
	PyObject_VAR_HEAD
	const char *tp_name;
	Py_ssize_t tp_basicsize, tp_itemsize;

	//...
	PyNumberMethods *tp_as_number;		//数值型操作
	PySequenceMethods *tp_as_sequence;	//序列型操作
	PyMappingMethods *tp_as_mapping;	//关联型操作

	//...
	PyBufferProcs *tp_as_buffer;
	//...
} PyTypeObject;
static PyNumberMethods float_as_number = {
	float_add,
	float_sub,
	float_mul,
	float_rem,
	float_divmod,
	float_pow,
	//...
};
PyTypeObject PyFloat_Type = {
	PyVarObject_HEAD_INIT(&PyType_Type, 0)
	"float",
	sizeof(PyFloatObject),

	&float_as_number,	// tp_as_number
	0,					// tp_as_sequence
	0,					// tp_as_mapping
};

只要类型对象提供相关的操作集,实例对象就会有这些行为。以float为例可以看到:
在PyFloat_Tpye类型对象中,定义了数值型操作集,序列型和关联型都是空的,所以只支持数值型操作,float_as_number中也详细对应了float版本的函数,有加减乘取余,取模等等。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值