深入理解Python虛擬機(jī)中復(fù)數(shù)(complex)的實現(xiàn)原理及源碼剖析
復(fù)數(shù)數(shù)據(jù)結(jié)構(gòu)
在 cpython 當(dāng)中對于復(fù)數(shù)的數(shù)據(jù)結(jié)構(gòu)實現(xiàn)如下所示:
typedef struct {
double real;
double imag;
} Py_complex;
#define PyObject_HEAD PyObject ob_base;
typedef struct {
PyObject_HEAD
Py_complex cval;
} PyComplexObject;
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;上面的數(shù)據(jù)結(jié)構(gòu)圖示如下:

復(fù)數(shù)的數(shù)據(jù)在整個 cpython 虛擬機(jī)當(dāng)中來說應(yīng)該算是比較簡單的了,除了一個 PyObject 頭部之外就是實部和虛部了。
- ob_refcnt,表示對象的引用記數(shù)的個數(shù),這個對于垃圾回收很有用處,后面我們分析虛擬機(jī)中垃圾回收部分在深入分析。
- ob_type,表示這個對象的數(shù)據(jù)類型是什么,在 python 當(dāng)中有時候需要對數(shù)據(jù)的數(shù)據(jù)類型進(jìn)行判斷比如 isinstance, type 這兩個關(guān)鍵字就會使用到這個字段。
- real,表示復(fù)數(shù)的實部。
- imag,表示復(fù)數(shù)的虛部。
復(fù)數(shù)的操作
復(fù)數(shù)加法
下面是 cpython 當(dāng)中對于復(fù)數(shù)加法的實現(xiàn),為了簡潔刪除了部分無用代碼。
static PyObject *
complex_add(PyObject *v, PyObject *w)
{
Py_complex result;
Py_complex a, b;
TO_COMPLEX(v, a); // TO_COMPLEX 這個宏的作用就是將一個 PyComplexObject 中的 Py_complex 對象存儲到 a 當(dāng)中
TO_COMPLEX(w, b);
result = _Py_c_sum(a, b); // 這個函數(shù)的具體實現(xiàn)在下方
return PyComplex_FromCComplex(result); // 這個函數(shù)的具體實現(xiàn)在下方
}
// 真正實現(xiàn)復(fù)數(shù)加法的函數(shù)
Py_complex
_Py_c_sum(Py_complex a, Py_complex b)
{
Py_complex r;
r.real = a.real + b.real;
r.imag = a.imag + b.imag;
return r;
}
PyObject *
PyComplex_FromCComplex(Py_complex cval)
{
PyComplexObject *op;
/* Inline PyObject_New */
// 申請內(nèi)存空間
op = (PyComplexObject *) PyObject_MALLOC(sizeof(PyComplexObject));
if (op == NULL)
return PyErr_NoMemory();
// 將這個對象的引用計數(shù)設(shè)置成 1
(void)PyObject_INIT(op, &PyComplex_Type);
// 將復(fù)數(shù)結(jié)構(gòu)體保存下來
op->cval = cval;
return (PyObject *) op;
}上面代碼的整體過程比較簡單:
- 首先先從 PyComplexObject 提取真正的復(fù)數(shù)部分。
- 將提取到的兩個復(fù)數(shù)進(jìn)行相加操作。
- 根據(jù)得到的結(jié)果在創(chuàng)建一個 PyComplexObject 對象,并且將這個對象返回。
復(fù)數(shù)取反
復(fù)數(shù)取反操作就是將實部和虛部取相反數(shù)就可以了,這個操作也比較簡單。
static PyObject *
complex_neg(PyComplexObject *v)
{
Py_complex neg;
neg.real = -v->cval.real;
neg.imag = -v->cval.imag;
return PyComplex_FromCComplex(neg);
}
PyObject *
PyComplex_FromCComplex(Py_complex cval)
{
PyComplexObject *op;
/* Inline PyObject_New */
op = (PyComplexObject *) PyObject_MALLOC(sizeof(PyComplexObject));
if (op == NULL)
return PyErr_NoMemory();
(void)PyObject_INIT(op, &PyComplex_Type);
op->cval = cval;
return (PyObject *) op;
}
Repr 函數(shù)
我們現(xiàn)在來介紹一下一個有趣的方法,就是復(fù)數(shù)類型的 repr 函數(shù),這個和類的 __repr__ 函數(shù)是作用是一樣的我們看一下復(fù)數(shù)的輸出是什么:
>>> data = complex(0, 1) >>> data 1j >>> data = complex(1, 1) >>> data (1+1j) >>> print(data) (1+1j)
復(fù)數(shù)的 repr 對應(yīng)的 C 函數(shù)如下所示:
static PyObject *
complex_repr(PyComplexObject *v)
{
int precision = 0;
char format_code = 'r';
PyObject *result = NULL;
/* If these are non-NULL, they'll need to be freed. */
char *pre = NULL;
char *im = NULL;
/* These do not need to be freed. re is either an alias
for pre or a pointer to a constant. lead and tail
are pointers to constants. */
char *re = NULL;
char *lead = "";
char *tail = "";
// 對應(yīng)實部等于 0 虛部大于 0 的情況
if (v->cval.real == 0. && copysign(1.0, v->cval.real)==1.0) {
/* Real part is +0: just output the imaginary part and do not
include parens. */
re = "";
im = PyOS_double_to_string(v->cval.imag, format_code,
precision, 0, NULL);
if (!im) {
PyErr_NoMemory();
goto done;
}
} else {
/* Format imaginary part with sign, real part without. Include
parens in the result. */
// 將實部浮點數(shù)變成字符串
pre = PyOS_double_to_string(v->cval.real, format_code,
precision, 0, NULL);
if (!pre) {
PyErr_NoMemory();
goto done;
}
re = pre;
// 將虛部浮點數(shù)變成字符串
im = PyOS_double_to_string(v->cval.imag, format_code,
precision, Py_DTSF_SIGN, NULL);
if (!im) {
PyErr_NoMemory();
goto done;
}
// 用什么括號包圍起來
lead = "(";
tail = ")";
}
result = PyUnicode_FromFormat("%s%s%sj%s", lead, re, im, tail);
done:
PyMem_Free(im);
PyMem_Free(pre);
return result;
}
我們現(xiàn)在修改源程序?qū)⑸厦娴?() 兩個括號變成 [],編譯之后執(zhí)行的結(jié)果如下所示:

可以看到括號變成了 [] 。
總結(jié)
在本篇文章當(dāng)中主要給大家介紹了在 cpython 虛擬機(jī)當(dāng)中對于復(fù)數(shù)這一類型的數(shù)據(jù)結(jié)構(gòu)以及他的具體實現(xiàn)。總體來說這個數(shù)據(jù)結(jié)構(gòu)比較簡單,操作也相對容易,比較容易理解,最后簡單介紹了一下復(fù)數(shù)類型的 repr 實現(xiàn),其實這個函數(shù)和 python 的類型系統(tǒng)有關(guān),目前我們還沒有仔細(xì)去討論這一點,在后續(xù)的文章當(dāng)中我們將深入的去學(xué)習(xí)這個知識點,現(xiàn)在我們就先了解其中部分函數(shù)即可。
到此這篇關(guān)于深入理解Python虛擬機(jī)中復(fù)數(shù)(complex)的實現(xiàn)原理及源碼剖析的文章就介紹到這了,更多相關(guān)Python虛擬機(jī) 復(fù)數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python實現(xiàn)統(tǒng)計文本文件字?jǐn)?shù)的方法
這篇文章主要介紹了Python實現(xiàn)統(tǒng)計文本文件字?jǐn)?shù)的方法,涉及Python針對文本文件讀取及字符串轉(zhuǎn)換、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下2017-05-05
解決python使用pd.read_csv()出現(xiàn)錯誤UnicodeDecodeError:?'utf-8&
你是否有過之前用pd.read打開csv文件都正常,但突然有一天運(yùn)行以前的代碼就突然報錯,這篇文章主要給大家介紹了關(guān)于如何解決python使用pd.read_csv()出現(xiàn)錯誤UnicodeDecodeError:?'utf-8'?codec?can't?decode......的相關(guān)資料,需要的朋友可以參考下2023-12-12
PyTorch上搭建簡單神經(jīng)網(wǎng)絡(luò)實現(xiàn)回歸和分類的示例
本篇文章主要介紹了PyTorch上搭建簡單神經(jīng)網(wǎng)絡(luò)實現(xiàn)回歸和分類的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04
Python使用原始字符串提高正則表達(dá)式效率的原因詳解
這篇文章主要給大家介紹了關(guān)于Python使用原始字符串提高正則表達(dá)式效率的相關(guān)資料,使用原始字符串(r"...")避免反斜杠轉(zhuǎn)義,簡化復(fù)雜模式,提升可讀性及維護(hù)性,是最佳實踐,需要的朋友可以參考下2025-05-05
Python實現(xiàn)Excel轉(zhuǎn)CSV高效轉(zhuǎn)換的實戰(zhàn)指南
在IT數(shù)據(jù)處理中,Excel與CSV是兩種常用格式,各自適用于復(fù)雜計算與輕量級數(shù)據(jù)交換,本文詳細(xì)介紹如何將Excel文件轉(zhuǎn)換為CSV格式,希望對大家有所幫助2025-10-10

