美文网首页
python容器-floatobject

python容器-floatobject

作者: dalewong | 来源:发表于2020-07-22 15:31 被阅读0次

    float定义:

    floatobject.h

    #ifndef Py_LIMITED_API
    typedef struct {
        PyObject_HEAD
        double ob_fval;
    } PyFloatObject;
    #endif
    

    从中我们可以看到PyFloatObject是由HEAD和double的ob_fval值组成,
    我们再查看HEAD的内容

    /* PyObject_HEAD defines the initial segment of every PyObject. */
    #define PyObject_HEAD                   PyObject ob_base;
    

    这里指向了PyObject这个结构体

    /* Nothing is actually declared to be a PyObject, but every pointer to
     * a Python object can be cast to a PyObject*.  This is inheritance built
     * by hand.  Similarly every pointer to a variable-size Python object can,
     * in addition, be cast to PyVarObject*.
     */
    typedef struct _object {
        _PyObject_HEAD_EXTRA
        Py_ssize_t ob_refcnt;
        struct _typeobject *ob_type;
    } PyObject;
    

    okay,我们看到Pyobject的组成,是由一个head_extra和obrefcnt和指向另一个结构体的_typeobeject组成
    head_extra

    #define _PyObject_HEAD_EXTRA            \
        struct _object *_ob_next;           \
        struct _object *_ob_prev;
    

    python活跃对象的双向链表

    #define _PyObject_EXTRA_INIT 0, 0
    define PyObject_HEAD_INIT(type)        \
        { _PyObject_EXTRA_INIT              \
        1, type },
    
    #define PyVarObject_HEAD_INIT(type, size)       \
        { PyObject_HEAD_INIT(type) size },
    

    根据类型来初始化PyObject

    typedef struct _object {
        _PyObject_HEAD_EXTRA
        Py_ssize_t ob_refcnt;
        struct _typeobject *ob_type;
    } PyObject;
    
    /* Cast argument to PyObject* type. */
    #define _PyObject_CAST(op) ((PyObject*)(op))
    
    typedef struct {
        PyObject ob_base;
        Py_ssize_t ob_size; /* Number of items in variable part */
    } PyVarObject;
    

    这里可以看到定长对象初始化引用计数1,边长对象增加了ob_size来记录了边长对象的元素的大小[如list, int]
    ob_refcnt是python的引用计数 继续查看_typeobject

    typedef struct _typeobject {
        PyObject_VAR_HEAD
        const char *tp_name; /* For printing, in format "<module>.<name>" */
        Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
    
        /* Methods to implement standard operations */
    
        destructor tp_dealloc;
        Py_ssize_t tp_vectorcall_offset;
        getattrfunc tp_getattr;
        setattrfunc tp_setattr;
        PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
                                        or tp_reserved (Python 3) */
        reprfunc tp_repr;
    
        /* Method suites for standard classes */
    
        PyNumberMethods *tp_as_number;
        PySequenceMethods *tp_as_sequence;
        PyMappingMethods *tp_as_mapping;
    
        /* More standard operations (here for binary compatibility) */
    
        hashfunc tp_hash;
        ternaryfunc tp_call;
        reprfunc tp_str;
        getattrofunc tp_getattro;
        setattrofunc tp_setattro;
    
        /* Functions to access object as input/output buffer */
        PyBufferProcs *tp_as_buffer;
    
        /* Flags to define presence of optional/expanded features */
        unsigned long tp_flags;
    
        const char *tp_doc; /* Documentation string */
    
        /* Assigned meaning in release 2.0 */
        /* call function for all accessible objects */
        traverseproc tp_traverse;
    
        /* delete references to contained objects */
        inquiry tp_clear;
    
        /* Assigned meaning in release 2.1 */
        /* rich comparisons */
        richcmpfunc tp_richcompare;
    
        /* weak reference enabler */
        Py_ssize_t tp_weaklistoffset;
    
        /* Iterators */
        getiterfunc tp_iter;
        iternextfunc tp_iternext;
    
        /* Attribute descriptor and subclassing stuff */
        struct PyMethodDef *tp_methods;
        struct PyMemberDef *tp_members;
        struct PyGetSetDef *tp_getset;
        struct _typeobject *tp_base;
        PyObject *tp_dict;
        descrgetfunc tp_descr_get;
        descrsetfunc tp_descr_set;
        Py_ssize_t tp_dictoffset;
        initproc tp_init;
        allocfunc tp_alloc;
        newfunc tp_new;
        freefunc tp_free; /* Low-level free-memory routine */
        inquiry tp_is_gc; /* For PyObject_IS_GC */
        PyObject *tp_bases;
        PyObject *tp_mro; /* method resolution order */
        PyObject *tp_cache;
        PyObject *tp_subclasses;
        PyObject *tp_weaklist;
        destructor tp_del;
    
        /* Type attribute cache version tag. Added in version 2.6 */
        unsigned int tp_version_tag;
    
        destructor tp_finalize;
        vectorcallfunc tp_vectorcall;
    
        /* bpo-37250: kept for backwards compatibility in CPython 3.8 only */
        Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
    
    #ifdef COUNT_ALLOCS
        /* these must be last and never explicitly initialized */
        Py_ssize_t tp_allocs;
        Py_ssize_t tp_frees;
        Py_ssize_t tp_maxalloc;
        struct _typeobject *tp_prev;
        struct _typeobject *tp_next;
    #endif
    } PyTypeObject;
    

    _typeobject

    1. PyObject_VAR_HEAD:
    typedef struct {
        PyObject ob_base;
        Py_ssize_t ob_size; /* Number of items in variable part */
    } PyVarObject;
    

    这里有趣的是typeobject指向了pyobject
    值得注意的是tp_call, 当初始化float(3.14)的时候,调用的是tp_call
    那tp_call是如何生成对应的float对象的呢

    PyTypeObject PyType_Type = {
        PyVarObject_HEAD_INIT(&PyType_Type, 0)
        "type",                                     /* tp_name */
        sizeof(PyHeapTypeObject),                   /* tp_basicsize */
        sizeof(PyMemberDef),                        /* tp_itemsize */
        (destructor)type_dealloc,                   /* tp_dealloc */
        0,                                          /* tp_vectorcall_offset */
        0,                                          /* tp_getattr */
        0,                                          /* tp_setattr */
        0,                                          /* tp_as_async */
        (reprfunc)type_repr,                        /* tp_repr */
        0,                                          /* tp_as_number */
        0,                                          /* tp_as_sequence */
        0,                                          /* tp_as_mapping */
        0,                                          /* tp_hash */
        (ternaryfunc)type_call,                     /* tp_call */
        0,                                          /* tp_str */
        (getattrofunc)type_getattro,                /* tp_getattro */
        (setattrofunc)type_setattro,                /* tp_setattro */
        0,                                          /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
            Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TYPE_SUBCLASS,         /* tp_flags */
        type_doc,                                   /* tp_doc */
        (traverseproc)type_traverse,                /* tp_traverse */
        (inquiry)type_clear,                        /* tp_clear */
        0,                                          /* tp_richcompare */
        offsetof(PyTypeObject, tp_weaklist),        /* tp_weaklistoffset */
        0,                                          /* tp_iter */
        0,                                          /* tp_iternext */
        type_methods,                               /* tp_methods */
        type_members,                               /* tp_members */
        type_getsets,                               /* tp_getset */
        0,                                          /* tp_base */
        0,                                          /* tp_dict */
        0,                                          /* tp_descr_get */
        0,                                          /* tp_descr_set */
        offsetof(PyTypeObject, tp_dict),            /* tp_dictoffset */
        type_init,                                  /* tp_init */
        0,                                          /* tp_alloc */
        type_new,                                   /* tp_new */
        PyObject_GC_Del,                            /* tp_free */
        (inquiry)type_is_gc,                        /* tp_is_gc */
    };
    

    查看typeobject.c中的定义的PyType_Type
    这里type_call指向了tp_call

    static PyObject *
    type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
    {
        PyObject *obj;
    
        if (type->tp_new == NULL) {
            PyErr_Format(PyExc_TypeError,
                         "cannot create '%.100s' instances",
                         type->tp_name);
            return NULL;
        }
    
    #ifdef Py_DEBUG
        /* type_call() must not be called with an exception set,
           because it can clear it (directly or indirectly) and so the
           caller loses its exception */
        assert(!PyErr_Occurred());
    #endif
    
        obj = type->tp_new(type, args, kwds);
        obj = _Py_CheckFunctionResult((PyObject*)type, obj, NULL);
        if (obj == NULL)
            return NULL;
    
        /* Ugly exception: when the call was type(something),
           don't call tp_init on the result. */
        if (type == &PyType_Type &&
            PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 &&
            (kwds == NULL ||
             (PyDict_Check(kwds) && PyDict_GET_SIZE(kwds) == 0)))
            return obj;
    
        /* If the returned object is not an instance of type,
           it won't be initialized. */
        if (!PyType_IsSubtype(Py_TYPE(obj), type))
            return obj;
    
        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;
    }
    

    调用type->tp_new生成object对象
    Py_TYPE(obj)把对象转换成type(指向自己的type)

    PyTypeObject PyFloat_Type = {
        PyVarObject_HEAD_INIT(&PyType_Type, 0)
        "float",
        sizeof(PyFloatObject),
        0,
        (destructor)float_dealloc,                  /* tp_dealloc */
        0,                                          /* tp_vectorcall_offset */
        0,                                          /* tp_getattr */
        0,                                          /* tp_setattr */
        0,                                          /* tp_as_async */
        (reprfunc)float_repr,                       /* tp_repr */
        &float_as_number,                           /* tp_as_number */
        0,                                          /* tp_as_sequence */
        0,                                          /* tp_as_mapping */
        (hashfunc)float_hash,                       /* tp_hash */
        0,                                          /* tp_call */
        0,                                          /* tp_str */
        PyObject_GenericGetAttr,                    /* tp_getattro */
        0,                                          /* tp_setattro */
        0,                                          /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
        float_new__doc__,                           /* tp_doc */
        0,                                          /* tp_traverse */
        0,                                          /* tp_clear */
        float_richcompare,                          /* tp_richcompare */
        0,                                          /* tp_weaklistoffset */
        0,                                          /* tp_iter */
        0,                                          /* tp_iternext */
        float_methods,                              /* tp_methods */
        0,                                          /* tp_members */
        float_getset,                               /* tp_getset */
        0,                                          /* tp_base */
        0,                                          /* tp_dict */
        0,                                          /* tp_descr_get */
        0,                                          /* tp_descr_set */
        0,                                          /* tp_dictoffset */
        0,                                          /* tp_init */
        0,                                          /* tp_alloc */
        float_new,                                  /* tp_new */
    };
    

    如上则是PyFloat_Type的定义
    初始化了tp_type为"float", 注意这时候tp_base为0

    PyStatus
    _PyTypes_Init(void)
    {
    #define INIT_TYPE(TYPE, NAME) \
        do { \
            if (PyType_Ready(TYPE) < 0) { \
                return _PyStatus_ERR("Can't initialize " NAME " type"); \
            } \
        } while (0)
    
        INIT_TYPE(&PyBaseObject_Type, "object");
        INIT_TYPE(&PyType_Type, "type");
        INIT_TYPE(&_PyWeakref_RefType, "weakref");
        INIT_TYPE(&_PyWeakref_CallableProxyType, "callable weakref proxy");
        INIT_TYPE(&_PyWeakref_ProxyType, "weakref proxy");
        INIT_TYPE(&PyLong_Type, "int");
        INIT_TYPE(&PyBool_Type, "bool");
        INIT_TYPE(&PyByteArray_Type, "bytearray");
        INIT_TYPE(&PyBytes_Type, "str");
        INIT_TYPE(&PyList_Type, "list");
        INIT_TYPE(&_PyNone_Type, "None");
        INIT_TYPE(&_PyNotImplemented_Type, "NotImplemented");
        INIT_TYPE(&PyTraceBack_Type, "traceback");
        INIT_TYPE(&PySuper_Type, "super");
        INIT_TYPE(&PyRange_Type, "range");
        INIT_TYPE(&PyDict_Type, "dict");
        INIT_TYPE(&PyDictKeys_Type, "dict keys");
        INIT_TYPE(&PyDictValues_Type, "dict values");
        INIT_TYPE(&PyDictItems_Type, "dict items");
        INIT_TYPE(&PyDictRevIterKey_Type, "reversed dict keys");
        INIT_TYPE(&PyDictRevIterValue_Type, "reversed dict values");
        INIT_TYPE(&PyDictRevIterItem_Type, "reversed dict items");
        INIT_TYPE(&PyODict_Type, "OrderedDict");
        INIT_TYPE(&PyODictKeys_Type, "odict_keys");
        INIT_TYPE(&PyODictItems_Type, "odict_items");
        INIT_TYPE(&PyODictValues_Type, "odict_values");
        INIT_TYPE(&PyODictIter_Type, "odict_keyiterator");
        INIT_TYPE(&PySet_Type, "set");
        INIT_TYPE(&PyUnicode_Type, "str");
        INIT_TYPE(&PySlice_Type, "slice");
        INIT_TYPE(&PyStaticMethod_Type, "static method");
        INIT_TYPE(&PyComplex_Type, "complex");
        INIT_TYPE(&PyFloat_Type, "float");
        INIT_TYPE(&PyFrozenSet_Type, "frozenset");
        INIT_TYPE(&PyProperty_Type, "property");
        INIT_TYPE(&_PyManagedBuffer_Type, "managed buffer");
        INIT_TYPE(&PyMemoryView_Type, "memoryview");
        INIT_TYPE(&PyTuple_Type, "tuple");
        INIT_TYPE(&PyEnum_Type, "enumerate");
        INIT_TYPE(&PyReversed_Type, "reversed");
        INIT_TYPE(&PyStdPrinter_Type, "StdPrinter");
        INIT_TYPE(&PyCode_Type, "code");
        INIT_TYPE(&PyFrame_Type, "frame");
        INIT_TYPE(&PyCFunction_Type, "builtin function");
        INIT_TYPE(&PyMethod_Type, "method");
        INIT_TYPE(&PyFunction_Type, "function");
        INIT_TYPE(&PyDictProxy_Type, "dict proxy");
        INIT_TYPE(&PyGen_Type, "generator");
        INIT_TYPE(&PyGetSetDescr_Type, "get-set descriptor");
        INIT_TYPE(&PyWrapperDescr_Type, "wrapper");
        INIT_TYPE(&_PyMethodWrapper_Type, "method wrapper");
        INIT_TYPE(&PyEllipsis_Type, "ellipsis");
        INIT_TYPE(&PyMemberDescr_Type, "member descriptor");
        INIT_TYPE(&_PyNamespace_Type, "namespace");
        INIT_TYPE(&PyCapsule_Type, "capsule");
        INIT_TYPE(&PyLongRangeIter_Type, "long range iterator");
        INIT_TYPE(&PyCell_Type, "cell");
        INIT_TYPE(&PyInstanceMethod_Type, "instance method");
        INIT_TYPE(&PyClassMethodDescr_Type, "class method descr");
        INIT_TYPE(&PyMethodDescr_Type, "method descr");
        INIT_TYPE(&PyCallIter_Type, "call iter");
        INIT_TYPE(&PySeqIter_Type, "sequence iterator");
        INIT_TYPE(&PyPickleBuffer_Type, "pickle.PickleBuffer");
        INIT_TYPE(&PyCoro_Type, "coroutine");
        INIT_TYPE(&_PyCoroWrapper_Type, "coroutine wrapper");
        INIT_TYPE(&_PyInterpreterID_Type, "interpreter ID");
        return _PyStatus_OK();
    
    #undef INIT_TYPE
    }
    

    这时候在object.c进行初始化操作,调用typeobject.c中的PyType_Ready

    int
    PyType_Ready(PyTypeObject *type)
    {
        // ...
    
        base = type->tp_base;
        if (base == NULL && type != &PyBaseObject_Type) {
            base = type->tp_base = &PyBaseObject_Type;
            Py_INCREF(base);
        }
    
        // ...
    }
    

    在typeobject中把Float_Type的base设置为type->tp_base.

    PyTypeObject PyBaseObject_Type = {
        PyVarObject_HEAD_INIT(&PyType_Type, 0)
        "object",                                   /* tp_name */
        sizeof(PyObject),                           /* tp_basicsize */
        0,                                          /* tp_itemsize */
        object_dealloc,                             /* tp_dealloc */
        0,                                          /* tp_vectorcall_offset */
        0,                                          /* tp_getattr */
        0,                                          /* tp_setattr */
        0,                                          /* tp_as_async */
        object_repr,                                /* tp_repr */
        0,                                          /* tp_as_number */
        0,                                          /* tp_as_sequence */
        0,                                          /* tp_as_mapping */
        (hashfunc)_Py_HashPointer,                  /* tp_hash */
        0,                                          /* tp_call */
        object_str,                                 /* tp_str */
        PyObject_GenericGetAttr,                    /* tp_getattro */
        PyObject_GenericSetAttr,                    /* tp_setattro */
        0,                                          /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
        object_doc,                                 /* tp_doc */
        0,                                          /* tp_traverse */
        0,                                          /* tp_clear */
        object_richcompare,                         /* tp_richcompare */
        0,                                          /* tp_weaklistoffset */
        0,                                          /* tp_iter */
        0,                                          /* tp_iternext */
        object_methods,                             /* tp_methods */
        0,                                          /* tp_members */
        object_getsets,                             /* tp_getset */
        0,                                          /* tp_base */
        0,                                          /* tp_dict */
        0,                                          /* tp_descr_get */
        0,                                          /* tp_descr_set */
        0,                                          /* tp_dictoffset */
        object_init,                                /* tp_init */
        PyType_GenericAlloc,                        /* tp_alloc */
        object_new,                                 /* tp_new */
        PyObject_Del,                               /* tp_free */
    };
    

    为什么要这么初始化呢,是因为所有的base都要有一个终点,否则就没有办法完成了。

    接着继续查看float_as_number装载了tp_as_number: 数字操作符,tp_as_sequence: 序列操作, tp_as_mapping: 映射操作,
    因为float只有数字操作,所以tp_as_sequence和tp_as_mapping都为0

    static PyNumberMethods float_as_number = {
        float_add,          /* nb_add */
        float_sub,          /* nb_subtract */
        float_mul,          /* nb_multiply */
        float_rem,          /* nb_remainder */
        float_divmod,       /* nb_divmod */
        float_pow,          /* nb_power */
        (unaryfunc)float_neg, /* nb_negative */
        float_float,        /* nb_positive */
        (unaryfunc)float_abs, /* nb_absolute */
        (inquiry)float_bool, /* nb_bool */
        0,                  /* nb_invert */
        0,                  /* nb_lshift */
        0,                  /* nb_rshift */
        0,                  /* nb_and */
        0,                  /* nb_xor */
        0,                  /* nb_or */
        float___trunc___impl, /* nb_int */
        0,                  /* nb_reserved */
        float_float,        /* nb_float */
        0,                  /* nb_inplace_add */
        0,                  /* nb_inplace_subtract */
        0,                  /* nb_inplace_multiply */
        0,                  /* nb_inplace_remainder */
        0,                  /* nb_inplace_power */
        0,                  /* nb_inplace_lshift */
        0,                  /* nb_inplace_rshift */
        0,                  /* nb_inplace_and */
        0,                  /* nb_inplace_xor */
        0,                  /* nb_inplace_or */
        float_floor_div,    /* nb_floor_divide */
        float_div,          /* nb_true_divide */
        0,                  /* nb_inplace_floor_divide */
        0,                  /* nb_inplace_true_divide */
    };
    

    以上则是float_as_number,数字操作的函数
    回到之前的函数, tp_init生成结果 查看floatobject.c.h

    static PyObject *
    float_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
    {
        PyObject *return_value = NULL;
        PyObject *x = _PyLong_Zero;
    
        if ((type == &PyFloat_Type) &&
            !_PyArg_NoKeywords("float", kwargs)) {
            goto exit;
        }
        if (!_PyArg_CheckPositional("float", PyTuple_GET_SIZE(args), 0, 1)) {
            goto exit;
        }
        if (PyTuple_GET_SIZE(args) < 1) {
            goto skip_optional;
        }
        x = PyTuple_GET_ITEM(args, 0);
    skip_optional:
        return_value = float_new_impl(type, x);
    
    exit:
        return return_value;
    }
    

    调用float_new_impl, 我们进一步查看

    static PyObject *
    float_new_impl(PyTypeObject *type, PyObject *x)
    /*[clinic end generated code: output=ccf1e8dc460ba6ba input=540ee77c204ff87a]*/
    {
        if (type != &PyFloat_Type)
            return float_subtype_new(type, x); /* Wimp out */
        /* If it's a string, but not a string subclass, use
           PyFloat_FromString. */
        if (PyUnicode_CheckExact(x))
            return PyFloat_FromString(x);
        return PyNumber_Float(x);
    }
    

    调用float_dubtype_new

    static PyObject *
    float_subtype_new(PyTypeObject *type, PyObject *x)
    {
        PyObject *tmp, *newobj;
    
        assert(PyType_IsSubtype(type, &PyFloat_Type));
        tmp = float_new_impl(&PyFloat_Type, x);
        if (tmp == NULL)
            return NULL;
        assert(PyFloat_Check(tmp));
        newobj = type->tp_alloc(type, 0);
        if (newobj == NULL) {
            Py_DECREF(tmp);
            return NULL;
        }
        ((PyFloatObject *)newobj)->ob_fval = ((PyFloatObject *)tmp)->ob_fval;
        Py_DECREF(tmp);
        return newobj;
    }
    

    这里给float对象分配内存
    回到floatobject.c,最后再给float对象ob_fval赋值
    float(3.14) = PyObject *float_new(float_type, 3.14)
    由于float是常量存在,查看floatobject.c中定义的PyFloat_Type,
    这里的tp_init是0,因为float是常数所以不需要额外操作

    最终我们可以得出Python的blue print的大致模型了:

    PyFloat_Type
    pyobject_head ---------> PyObject
              _typeobject------------> PyType_Type
                            |tp_base
    tp_base --------------------------------------> PyBaseObject_Type

    相关文章

      网友评论

          本文标题:python容器-floatobject

          本文链接:https://www.haomeiwen.com/subject/culgkktx.html