当前位置: 首页 > Linux

深入理解Python虚拟机:复数(complex)实现原理及源码分析

时间:2023-04-07 03:14:26 Linux

深入理解Python虚拟机:复数(complex)实现原理及源码分析复杂数据类型如何实现,这个数据类型应该是cpython中比较简单的一种数据类型,非常容易理解。cpython中复杂数据结构的实现如下:typedefstruct{doublereal;双图像;}Py_complex;#definePyObject_HEADPyObjectob_base;typedefstruct{PyObject_HEADPy_complexcval;}PyComplexObject;typedefstruct_object{_PyObject_sHEAD_EXTRAize_Pyob_refcnt;struct_typeobject*ob_type;}PyObject;上面的数据结构图如下:复杂的数据在整个cpython虚拟机中应该算是比较简单的,除了一个PyObject头是实部和虚部。ob_refcnt,表示对象的引用计数数,对垃圾回收很有用。后面我们会深入分析虚拟机的垃圾回收部分。ob_type,表示这个对象的数据类型。在python中,有时候需要判断数据的数据类型,比如isinstance和type,这两个关键字都会用到这个字段。real,表示复数的实部。imag,表示复数的虚部。复数运算复数加法下面是复数加法在cpython中的实现,为了简洁删除了一些无用的代码。staticPyObject*complex_add(PyObject*v,PyObject*w){Py_complex结果;Py_complexa,b;TO_COMPLEX(v,a);//TO_COMPLEX这个宏就是把PyComplexObject中的Py_complex对象存入一个TO_COMPLEX(w,b);结果=_Py_c_sum(a,b);//该函数的具体实现如下returnPyComplex_FromCComplex(result);//这个函数的具体实现如下}//真正实现复数加法的函数Py_complex_Py_c_sum(Py_complexa,Py_complexb){Py_complexr;r.real=a.real+b.real;r.imag=a.imag+b.imag;返回r;}PyObject*PyComplex_FromCComplex(Py_complexcval){PyComplexObject*op;/*InlinePyObject_New*///申请内存空间op=(PyComplexObject*)PyObject_MALLOC(sizeof(PyComplexObject));如果(op==NULL)返回PyErr_NoMemory();//将此对象的引用计数设置为1(void)PyObject_INIT(op,&PyComplex_Type);//保存复杂结构op->cval=cval;return(PyObject*)op;}上面代码的整体过程比较简单:首先从PyComplexObject中提取出真正复杂的部分。将提取的两个复数相加。根据得到的结果创建一个PyComplexObject对象,并返回这个对象。复数取反运算就是将实部和虚部取反,这个运算比较简单。静态PyObject*complex_neg(PyComplexObject*v){Py_complexneg;neg.real=-v->cval.real;neg.imag=-v->cval.imag;返回PyComplex_FromCComplex(neg);}PyObject*PyComplex_FromCComplex(Py_complexcval){PyComplexObject*op;/*内联PyObject_New*/op=(PyComplexObject*)PyObject_MALLOC(sizeof(PyComplexObject));如果(op==NULL)返回PyErr_NoMemory();(void)PyObject_INIT(op,&PyComplex_Type);op->cval=cval;return(PyObject*)op;}reprfunction下面介绍一个比较有意思的方法,就是复数类型的repr函数,和类的\_\_repr\_\_函数是一样的,来看看复数是什么输出是:>>>data=complex(0,1)>>>data1j>>>data=complex(1,1)>>>data(1+1j)>>>print(data)(1+1j)复数repr对应的C函数如下:staticPyObject*complex_repr(PyComplexObject*v){intprecision=0;字符格式代码='r';PyObject*结果=NULL;/*如果这些是非NULL,则需要释放它们。*/char*pre=NULL;字符*im=NUL;/*这些不需要被释放。re是pre的别名或指向常量的指针。lead和tail是指向常量的指针。*/字符*re=NULL;炭*铅=“”;*尾巴=“”;//对应实部等于0,虚部大于0的情况if(v->cval.real==0.&©sign(1.0,v->cval.real)==1.0){/*实部为+0:只输出虚部,不包含括号。*/重新=“”;im=PyOS_double_to_string(v->cval.imag,format_code,precision,0,NULL);如果(!im){PyErr_NoMemory();完成;}}else{/*格式化虚部带符号,实部不带符号。在结果中包含括号。*///将实部浮点数转为字符串pre=PyOS_double_to_string(v->cval.real,format_code,precision,0,NULL);如果(!pre){PyErr_No内存();完成;}重新=预;//将虚部浮点数转换为字符串im=PyOS_double_to_string(v->cval.imag,format_code,precision,Py_DTSF_SIGN,NULL);如果(!im){PyErr_NoMemory();完成;}//括号括起来lead="(";tail=")";}result=PyUnicode_FromFormat("%s%s%sj%s",lead,re,im,tail);完成:PyMem_Free(im);PyMem_Free(预);returnresult;}现在我们修改源程序,把上面两个括号()改成[],编译后的执行结果如下:可以看到括号变成了[]小结本文主要介绍复杂的数据结构及其在cpython虚拟机中的具体实现。一般来说,数据结构比较简单,操作比较容易,也比较容易理解。最后简单介绍一下复杂类型的repr实现。其实这个函数和python的类型系统有关。目前我们还没有详细讨论这个问题。在后续的文章中,我们会深入学习这个知识点,现在只需要了解其中的部分功能即可。本文是深入理解python虚拟机系列文章之一。文章地址为:https://github.com/Chang-LeHung/dive-into-cpython更多精彩内容合集可访问:https://github.com/Chang-LeHung/CSCore关注公众号:废柴研究僧,多学点计算机(Java,Python,计算机系统基础,算法和数据结构)。

最新推荐
猜你喜欢