从源码看Python的descriptor

栏目: Python · 发布时间: 6年前

内容简介:descriptor是Python初学者比较不好懂的概念之一,再加上官网文档说的也不是很清楚, 就更容易让人误解了。但是源码总不会说不清楚,所以我们从源码看清楚descriptor到底 在干啥。所以可以得知:

descriptor是 Python 初学者比较不好懂的概念之一,再加上官网文档说的也不是很清楚, 就更容易让人误解了。但是源码总不会说不清楚,所以我们从源码看清楚descriptor到底 在干啥。

PyObject *
_PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict)
{
    /* Make sure the logic of _PyObject_GetMethod is in sync with
       this method.
    */

    PyTypeObject *tp = Py_TYPE(obj);
    PyObject *descr = NULL;
    PyObject *res = NULL;
    descrgetfunc f;
    Py_ssize_t dictoffset;
    PyObject **dictptr;

    if (!PyUnicode_Check(name)){
        PyErr_Format(PyExc_TypeError,
                     "attribute name must be string, not '%.200s'",
                     name->ob_type->tp_name);
        return NULL;
    }
    Py_INCREF(name);

    if (tp->tp_dict == NULL) {
        if (PyType_Ready(tp) < 0)
            goto done;
    }

    descr = _PyType_Lookup(tp, name);  // 从自身包括继承关系中找descriptor

    f = NULL;
    if (descr != NULL) {
        Py_INCREF(descr);
        f = descr->ob_type->tp_descr_get;
        if (f != NULL && PyDescr_IsData(descr)) {
        // 如果有descriptor并且是data descriptor,那么就调用并返回
            res = f(descr, obj, (PyObject *)obj->ob_type);
            goto done;
        }
    }

    if (dict == NULL) {
        /* Inline _PyObject_GetDictPtr */
        dictoffset = tp->tp_dictoffset;
        if (dictoffset != 0) {
            if (dictoffset < 0) {
                Py_ssize_t tsize;
                size_t size;

                tsize = ((PyVarObject *)obj)->ob_size;
                if (tsize < 0)
                    tsize = -tsize;
                size = _PyObject_VAR_SIZE(tp, tsize);
                assert(size <= PY_SSIZE_T_MAX);

                dictoffset += (Py_ssize_t)size;
                assert(dictoffset > 0);
                assert(dictoffset % SIZEOF_VOID_P == 0);
            }
            dictptr = (PyObject **) ((char *)obj + dictoffset);
            dict = *dictptr;
        }
    }
    if (dict != NULL) {
        Py_INCREF(dict);
        // 从__dict__里查找属性并返回
        res = PyDict_GetItem(dict, name);
        if (res != NULL) {
            Py_INCREF(res);
            Py_DECREF(dict);
            goto done;
        }
        Py_DECREF(dict);
    }

    if (f != NULL) {
        // 非data descriptor,返回
        res = f(descr, obj, (PyObject *)Py_TYPE(obj));
        goto done;
    }

    if (descr != NULL) {
        res = descr;
        descr = NULL;
        goto done;
    }

    PyErr_Format(PyExc_AttributeError,
                 "'%.50s' object has no attribute '%U'",
                 tp->tp_name, name);
  done:
    Py_XDECREF(descr);
    Py_DECREF(name);
    return res;
}

PyObject *
PyObject_GenericGetAttr(PyObject *obj, PyObject *name)
{
    // 调用此函数,往上看
    return _PyObject_GenericGetAttrWithDict(obj, name, NULL);
}

所以可以得知:

- descriptor是作为属性时才会生效,如下demo中,Foo是作为属性时,才会生效
- 属性查找顺序为 data descriptor -> __dict__ -> descriptor
In [1]: class Foo:
   ...:     def __get__(self, obj, type):
   ...:         print("__get__")
   ...:     def __set__(self, obj, val):
   ...:         print("__set__")
   ...:

In [2]: class Test:
   ...:     bar = Foo()
   ...:

In [3]: t = Test()

In [4]: t.bar
__get__

In [5]: foo = Foo()

In [6]: foo.bar
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-6-673afadb7b8e> in <module>()
----> 1 foo.bar

AttributeError: 'Foo' object has no attribute 'bar'

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

来吧!带你玩转 Excel VBA

来吧!带你玩转 Excel VBA

罗刚君、杨嘉恺 / 电子工业出版社 / 2013-7 / 85.00元

本书旨在普及Excel VBA 基础理论,以及通过VBA 的高级应用扩展Excel 的功能,提升读者的制表效率,解决工作中的疑难,同时亦可借此开发商业插件。 本书主要分为操作自动化引言篇、入门篇、进阶篇和疑难解答篇,覆盖从入门到提高的所有内容,以满足不同层次的读者需求。其中操作自动化引言篇简述了操作自动化的需求与方式,借此引出VBA 入门篇。VBA 入门篇包含第2 章到第13 章,主要介绍了......一起来看看 《来吧!带你玩转 Excel VBA》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具