前言

前面说过,Python3支持intfloatcomplex(复数)3种Number数据类型,本章主要介绍complex

complex

类型对象

complex同样是一个类型对象,其定义在Python/bltinmodule.c文件中:

...
    SETBUILTIN("classmethod",           &PyClassMethod_Type);
    SETBUILTIN("complex",               &PyComplex_Type);
    SETBUILTIN("dict",                  &PyDict_Type);
...

对应着定义在Objects/complexobject.cPyComplex_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);
}

说明:

  1. 复数由实数部分和虚数部分构成,可以用 a + bj,或者 complex(a, b) 表示,从上边的代码可以看出,复数的实部a和虚部b都存储为了浮点型;
  2. complex(a, b),当第一个参数为字符串时,不允许出现第二个参数;
  3. complex(a, b),第二个参数不允许是字符串;
  4. complex(a, b),第一个参数必须是字符串或者数字;
  5. 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)
>>>
Copyright © itrunner.cn 2020 all right reserved,powered by Gitbook该文章修订时间: 2022-08-28 07:44:16

results matching ""

    No results matching ""