__dir__ 到底是如何实现的,我应该如何知道它?

lai*_*e9m 2 python python-internals

所以我想了解dir()功能的细节。首先我查看了它的实现: https://github.com/python/cpython/blob/e76daebc0c8afa3981a4c5a8b54537f756e805de/Objects/object.c#L1450-L1477

/* Helper for PyObject_Dir: object introspection. */
static PyObject *
_dir_object(PyObject *obj)
{
    PyObject *result, *sorted;
    PyObject *dirfunc = _PyObject_LookupSpecial(obj, &PyId___dir__);

    assert(obj);
    if (dirfunc == NULL) {
        if (!PyErr_Occurred())
            PyErr_SetString(PyExc_TypeError, "object does not provide __dir__");
        return NULL;
    }
    /* use __dir__ */
    result = _PyObject_CallNoArg(dirfunc);
    Py_DECREF(dirfunc);
    if (result == NULL)
        return NULL;
    /* return sorted(result) */
    sorted = PySequence_List(result);
    Py_DECREF(result);
    if (sorted == NULL)
        return NULL;
    if (PyList_Sort(sorted)) {
        Py_DECREF(sorted);
        return NULL;
    }
    return sorted;
}
Run Code Online (Sandbox Code Playgroud)

并发现该_dir_object函数本身并没有做任何工作,而是调用了__dir__内省对象的方法。

>>> def test(): pass
>>> test.__dir__
<built-in method __dir__ of function object at 0x10ee57ae8>
Run Code Online (Sandbox Code Playgroud)

那么如何知道它的执行情况呢?

Mar*_*ers 5

__dir__是一个特殊的方法,所以至少在Python 3中查找类型:

\n
>>> type(test)\n<class \'function\'>\n>>> \'__dir__\' in dir(type(test))\nTrue\n>>> type(test).__dir__\n<method \'__dir__\' of \'object\' objects>\n>>> dir(test) == sorted(type(test).__dir__(test))\nTrue\n
Run Code Online (Sandbox Code Playgroud)\n

请参阅数据模型的特殊方法查找部分:

\n
\n

对于自定义类,只有在 object\xe2\x80\x99s 类型上定义特殊方法的隐式调用才能保证正确工作,而不是在 object\xe2\x80\x99s 实例字典中定义。

\n
\n

这正是该_PyObject_LookupSpecial()函数的作用,请参阅代码typeobject.c

\n
>>> type(test)\n<class \'function\'>\n>>> \'__dir__\' in dir(type(test))\nTrue\n>>> type(test).__dir__\n<method \'__dir__\' of \'object\' objects>\n>>> dir(test) == sorted(type(test).__dir__(test))\nTrue\n
Run Code Online (Sandbox Code Playgroud)\n

那里的调用Py_TYPE()是重要的部分,是在类型__dir__上查找的。

\n

方法__dir__是在object类型上实现的,并由函数类型继承,因此实现在函数object_dir()

\n

对于Python 2,dir()实现更加精细,而且实际上还委托给其他函数!对于函数对象,它委托给_generic_dir()function。该函数参考__dict__以下类型:

\n
res = _PyType_LookupId(Py_TYPE(self), attrid);\n
Run Code Online (Sandbox Code Playgroud)\n

其中merge_class_dict()递归地将类层次结构属性合并到最终结果中。

\n