Python 3+ 一切都是对象

yufei       6 年, 5 月 前       2146

对于 Python 来说,一切都是对象 。 这句话很重要,当你对某个特性不了解时,回想下这句话也许就能想通

一个整数一个对象,一个浮点数也是一个对象,一个函数也是一个对象

>>> isinstance(3,object)
True
>>> isinstance(3.14, object)
True
>>> isinstance(max,object)
True

既然一切都是对象,那么这一切应该都有一个类来创建。它们都有一个公共的基础类,这个基础类就是 object

一切都是对象

object

如果我们使用 type() 函数来检查下它们的类型,就会发现

>>> type(1)
<class 'int'>
>>> type(1)
<class 'int'>
>>> type(3.14)
<class 'float'>
>>> type(max)
<class 'builtin_function_or_method'>

那么 intfloatbuiltin_function_or_method 又是什么呢?

>>> type(int)
<class 'type'>
>>> type(int)
<class 'type'>
>>> type(float)
<class 'type'>
>>> type(builtin_function_or_method)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'builtin_function_or_method' is not defined

但,其实,object 也是一个对象

>>> type(object)
<class 'type'>

type()

看到这里,想必对 type 这个类型很好奇,到底是什么鬼?

一探究竟的事情,我们等下再说,我们先来了解下 type() 函数的原理

type() 函数是一个内建可调用类,只有一个参数的情况下,它的作用相当于访问参数的 __class__ 属性

>>> type(int)
<class 'type'>
>>> int.__class__
<class 'type'>

更有意思的是,type(type) 的结果还算是 <class 'type'>

>>> type(type)
<class 'type'>
>>> type.__class__
<class 'type'>

什么意思,也就是自己创建了自己? 这....

越挖越深,算了,以后有篇幅再来讲解 type()

我们先挖一下源码,因为 type()intfloat 都说是内建函数,所以我们找到内建函数的源码

Python 目录下的 bltinmodule.c 文件中的第 2892 行开始

SETBUILTIN("None",                  Py_None);
SETBUILTIN("Ellipsis",              Py_Ellipsis);
SETBUILTIN("NotImplemented",        Py_NotImplemented);
SETBUILTIN("False",                 Py_False);
SETBUILTIN("True",                  Py_True);
SETBUILTIN("bool",                  &PyBool_Type);
SETBUILTIN("memoryview",        &PyMemoryView_Type);
SETBUILTIN("bytearray",             &PyByteArray_Type);
SETBUILTIN("bytes",                 &PyBytes_Type);
SETBUILTIN("classmethod",           &PyClassMethod_Type);
SETBUILTIN("complex",               &PyComplex_Type);
SETBUILTIN("dict",                  &PyDict_Type);
SETBUILTIN("enumerate",             &PyEnum_Type);
SETBUILTIN("filter",                &PyFilter_Type);
SETBUILTIN("float",                 &PyFloat_Type);
SETBUILTIN("frozenset",             &PyFrozenSet_Type);
SETBUILTIN("property",              &PyProperty_Type);
SETBUILTIN("int",                   &PyLong_Type);
SETBUILTIN("list",                  &PyList_Type);
SETBUILTIN("map",                   &PyMap_Type);
SETBUILTIN("object",                &PyBaseObject_Type);
SETBUILTIN("range",                 &PyRange_Type);
SETBUILTIN("reversed",              &PyReversed_Type);
SETBUILTIN("set",                   &PySet_Type);
SETBUILTIN("slice",                 &PySlice_Type);
SETBUILTIN("staticmethod",          &PyStaticMethod_Type);
SETBUILTIN("str",                   &PyUnicode_Type);
SETBUILTIN("super",                 &PySuper_Type);
SETBUILTIN("tuple",                 &PyTuple_Type);
SETBUILTIN("type",                  &PyType_Type);
SETBUILTIN("zip",                   &PyZip_Type);

可以看到

  1. int 是一个对 PyLong_Type 的引用
  2. float 是一个对 PyFloat_Type 的引用
  3. object 是一个对 PyBaseObject_Type 的引用
  4. type 是一个对 PyType_Type 的引用

继续追查,我们可以看到如下定义

Include/longobject.h

PyAPI_DATA(PyTypeObject) PyLong_Type;

Include/floatobject.h

PyAPI_DATA(PyTypeObject) PyFloat_Type;

Include/object.h

PyAPI_DATA(PyTypeObject) PyType_Type; /* built-in 'type' */
PyAPI_DATA(PyTypeObject) PyBaseObject_Type; /* built-in 'object' */
PyAPI_DATA(PyTypeObject) PySuper_Type; /* built-in 'super' */

所以,接下来我们就想知道 PyAPI_DATA 是什么鬼,这个在 pyport.h 中定义

#ifndef PyAPI_DATA
#       define PyAPI_DATA(RTYPE) extern RTYPE
#endif

也就是说,经过预处理之后,它们就是下面这样

PyTypeObject PyLong_Type;
PyTypeObject PyFloat_Type
PyTypeObject PyType_Type; 
PyTypeObject PyBaseObject_Type;
PyTypeObject PySuper_Type; 

是什么意思呢? 它们都是 PyTypeObject 结构体的一个变量,所以它们的终极类型,结果都是 type

因为它们都是函数,这些函数都会传入一个字面量,然后返回一个对应类型的实例

所以,我们就要知道 PyTypeObject 到底是什么

#ifdef Py_LIMITED_API
typedef struct _typeobject PyTypeObject; /* opaque */
#else
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;
    printfunc tp_print;
    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;

#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;
#endif

结构体成员很多,我们只要记住第二个结构体成员 tp_name 就好,它表示当前的对象的类型

比如 PyLongType 在初始化的时候是这样的

Objects/longobject.c

PyTypeObject PyLong_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "int",                                      /* tp_name */
    offsetof(PyLongObject, ob_digit),           /* tp_basicsize */
    sizeof(digit),                              /* tp_itemsize */
    long_dealloc,                               /* tp_dealloc */
    0,                                          /* tp_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_reserved */
    long_to_decimal_string,                     /* tp_repr */
    &long_as_number,                            /* tp_as_number */
    0,                                          /* tp_as_sequence */
    0,                                          /* tp_as_mapping */
    (hashfunc)long_hash,                        /* tp_hash */
    0,                                          /* tp_call */
    long_to_decimal_string,                     /* tp_str */
    PyObject_GenericGetAttr,                    /* tp_getattro */
    0,                                          /* tp_setattro */
    0,                                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
        Py_TPFLAGS_LONG_SUBCLASS,               /* tp_flags */
    long_doc,                                   /* tp_doc */
    0,                                          /* tp_traverse */
    0,                                          /* tp_clear */
    long_richcompare,                           /* tp_richcompare */
    0,                                          /* tp_weaklistoffset */
    0,                                          /* tp_iter */
    0,                                          /* tp_iternext */
    long_methods,                               /* tp_methods */
    0,                                          /* tp_members */
    long_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 */
    long_new,                                   /* tp_new */
    PyObject_Del,                               /* tp_free */
};

可以看到第二个参数 tp_name 就被设置为 "int"

同样的,我们可以看到 PyBaseObject_Type 变量的初始化为

typeobject.c

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_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_reserved */
    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 */
    PyDoc_STR("object()\n--\n\nThe most base type"),  /* 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 */
};

tp_name 成员变量被设置为 object

同时在 typeobject.c 中还可以看到 PyType_Type 变量的初始化

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_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_reserved */
    (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 */
};

到此为止,我们已经了解了每隔类型的内建函数 int()float() 的创建过程,也知道了 type() 函数第一次的返回值

PyObject_VAR_HEAD

接下来我们所要了解的是,为什么

>>> type(int)
<class 'type'>
>>> type(object)
<class 'type'>
>>> type(type)
<class 'type'>

这就涉及到 type() 函数的实现了,我们知道,PyType_TypePyBaseObject_TypePyLong_Type 都是的成员变量 tp_base 都是 0 ,也就是说它们都没有基类

但是大家有没有发现另一个有趣的成员变量,就是 PyObject_VAR_HEAD

可以说,几乎所有的类型都有这个成员变量,它,就是继承链条,它用于表示当前类型在所有继承体系中的为止

我们来看看它的实现

Include/object.h

#define PyObject_VAR_HEAD      PyVarObject ob_base;

而这个成员变量的初始化方式都是

PyVarObject_HEAD_INIT(&PyType_Type, 0)

也就是说,PyObject_VAR_HEAD 实际上是 PyVarObject 的一个实例

PyVarObject 又是什么呢?

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

PyVarObject 包含了一个 PyObject 的实例,那么 PyObject 又是什么呢?

typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

看到这,是不是很明朗了,struct _typeobject 就是 PyTypeObject

_PyObject_HEAD_EXTRA 的实现如下

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

所以,这条继承链就很清楚了,也能理解为什么 type(int)==type(type)

Python 中所有的对象,都是由此而成,可能你很费解,那么 intobject 其实没有任何的,对吧,我们再下一章节再来学习

目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.