前言
前面说过,Python3支持int
、float
、complex
(复数)3种Number
数据类型,本章主要介绍complex
。
complex
类型对象
complex
同样是一个类型对象,其定义在Python/bltinmodule.c
文件中:
...
SETBUILTIN("classmethod", &PyClassMethod_Type);
SETBUILTIN("complex", &PyComplex_Type);
SETBUILTIN("dict", &PyDict_Type);
...
对应着定义在Objects/complexobject.c
的PyComplex_Type
:
PyTypeObject PyComplex_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"complex",
sizeof(PyComplexObject),
0,
complex_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
(reprfunc)complex_repr, /* tp_repr */
&complex_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)complex_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)complex_repr, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
complex_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
complex_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
complex_methods, /* tp_methods */
complex_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
complex_new, /* tp_new */
PyObject_Del, /* tp_free */
};
complex对象的创建
complex
通过complex_new
生成complex
对象。
static PyObject *
complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *r, *i, *tmp;
PyNumberMethods *nbr, *nbi = NULL;
Py_complex cr, ci;
int own_r = 0;
int cr_is_complex = 0;
int ci_is_complex = 0;
static char *kwlist[] = {"real", "imag", 0};
r = Py_False;
i = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:complex", kwlist,
&r, &i))
return NULL;
/* Special-case for a single argument when type(arg) is complex. */
if (PyComplex_CheckExact(r) && i == NULL &&
type == &PyComplex_Type) {
/* Note that we can't know whether it's safe to return
a complex *subclass* instance as-is, hence the restriction
to exact complexes here. If either the input or the
output is a complex subclass, it will be handled below
as a non-orthogonal vector. */
Py_INCREF(r);
return r;
}
if (PyUnicode_Check(r)) {
if (i != NULL) {
PyErr_SetString(PyExc_TypeError,
"complex() can't take second arg"
" if first is a string");
return NULL;
}
return complex_subtype_from_string(type, r);
}
if (i != NULL && PyUnicode_Check(i)) {
PyErr_SetString(PyExc_TypeError,
"complex() second arg can't be a string");
return NULL;
}
tmp = try_complex_special_method(r);
if (tmp) {
r = tmp;
own_r = 1;
}
else if (PyErr_Occurred()) {
return NULL;
}
nbr = r->ob_type->tp_as_number;
if (nbr == NULL || nbr->nb_float == NULL) {
PyErr_Format(PyExc_TypeError,
"complex() first argument must be a string or a number, "
"not '%.200s'",
Py_TYPE(r)->tp_name);
if (own_r) {
Py_DECREF(r);
}
return NULL;
}
if (i != NULL) {
nbi = i->ob_type->tp_as_number;
if (nbi == NULL || nbi->nb_float == NULL) {
PyErr_Format(PyExc_TypeError,
"complex() second argument must be a number, "
"not '%.200s'",
Py_TYPE(i)->tp_name);
if (own_r) {
Py_DECREF(r);
}
return NULL;
}
}
/* If we get this far, then the "real" and "imag" parts should
both be treated as numbers, and the constructor should return a
complex number equal to (real + imag*1j).
Note that we do NOT assume the input to already be in canonical
form; the "real" and "imag" parts might themselves be complex
numbers, which slightly complicates the code below. */
if (PyComplex_Check(r)) {
/* Note that if r is of a complex subtype, we're only
retaining its real & imag parts here, and the return
value is (properly) of the builtin complex type. */
cr = ((PyComplexObject*)r)->cval;
cr_is_complex = 1;
if (own_r) {
Py_DECREF(r);
}
}
else {
/* The "real" part really is entirely real, and contributes
nothing in the imaginary direction.
Just treat it as a double. */
tmp = PyNumber_Float(r);
if (own_r) {
/* r was a newly created complex number, rather
than the original "real" argument. */
Py_DECREF(r);
}
if (tmp == NULL)
return NULL;
if (!PyFloat_Check(tmp)) {
PyErr_SetString(PyExc_TypeError,
"float(r) didn't return a float");
Py_DECREF(tmp);
return NULL;
}
cr.real = PyFloat_AsDouble(tmp);
cr.imag = 0.0;
Py_DECREF(tmp);
}
if (i == NULL) {
ci.real = cr.imag;
}
else if (PyComplex_Check(i)) {
ci = ((PyComplexObject*)i)->cval;
ci_is_complex = 1;
} else {
/* The "imag" part really is entirely imaginary, and
contributes nothing in the real direction.
Just treat it as a double. */
tmp = (*nbi->nb_float)(i);
if (tmp == NULL)
return NULL;
ci.real = PyFloat_AsDouble(tmp);
Py_DECREF(tmp);
}
/* If the input was in canonical form, then the "real" and "imag"
parts are real numbers, so that ci.imag and cr.imag are zero.
We need this correction in case they were not real numbers. */
if (ci_is_complex) {
cr.real -= ci.imag;
}
if (cr_is_complex && i != NULL) {
ci.real += cr.imag;
}
return complex_subtype_from_doubles(type, cr.real, ci.real);
}
说明:
- 复数由实数部分和虚数部分构成,可以用
a + bj
,或者complex(a, b)
表示,从上边的代码可以看出,复数的实部a
和虚部b
都存储为了浮点型; complex(a, b)
,当第一个参数为字符串时,不允许出现第二个参数;complex(a, b)
,第二个参数不允许是字符串;complex(a, b)
,第一个参数必须是字符串或者数字;complex(a, b)
,第二个参数必须是数字;
示例:
Python 3.6.4 (v3.6.4:d48ecebad5, Dec 18 2017, 21:07:28)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> complex("1.0", 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: complex() can't take second arg if first is a string
>>> complex(1, "2")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: complex() second arg can't be a string
>>> complex([1], 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: complex() first argument must be a string or a number, not 'list'
>>> complex(1, [2])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: complex() second argument must be a number, not 'list'
>>> complex(1.0, 2.0)
(1+2j)
>>>