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

How is __dir__ implemented exactly, and how should I know it?

所以我想知道 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;
}

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

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

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

__dir__特殊方法,所以查了一下类型,至少在Python3:

>>> type(test)
<class 'function'>
>>> '__dir__' in dir(type(test))
True
>>> type(test).__dir__
<method '__dir__' of 'object' objects>
>>> dir(test) == sorted(type(test).__dir__(test))
True

查看数据模型的Special method lookup section

For custom classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary.

这正是 _PyObject_LookupSpecial() 函数的作用,参见 the typeobject.c source code:

res = _PyType_LookupId(Py_TYPE(self), attrid);

那里的 Py_TYPE() 调用是重要的部分,__dir__type.

上查找

__dir__方法是在object类型上实现的,被function类型继承,所以实现在object_dir() function.

为Python 2、dir() implementation is more elaborate, and actually also delegates to other functions! For function objects, it delegates to the _generic_dir() function。此函数参考类型的__dict__

/* Merge in attrs reachable from its class. */
itsclass = PyObject_GetAttrString(obj, "__class__");
if (itsclass == NULL)
    /* XXX(tomer): Perhaps fall back to obj->ob_type if no
                   __class__ exists? */
    PyErr_Clear();
else {
    if (merge_class_dict(dict, itsclass) != 0)
        goto error;
}

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

您正在查看的代码来自最近的 Python 版本,但您正在测试旧版本。

在新版本中,自动为所有类型提供实现 __dir__

在旧版本中,除非手动提供,否则对象没有__dir__。然后实施会在 _dir_object 中考虑到这一点。这是来自 Python 2.7:

if (dirfunc == NULL) {
    /* use default implementation */
    if (PyModule_Check(obj))
        result = _specialized_dir_module(obj);
    else if (PyType_Check(obj) || PyClass_Check(obj))
        result = _specialized_dir_type(obj);
    else
        result = _generic_dir(obj);
}

Python3中object.__dir__的实现见Objects/typeobject.c中的object___dir___impl