如何__dir__完全实现,我该怎么知道呢?

时间:2018-02-04 14:27:25

标签: 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;
}

发现_dir_object函数本身不做任何工作,但调用了内省对象的__dir__方法。

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

那么如何知道它的实现呢?

2 个答案:

答案 0 :(得分:4)

__dir__是一个特殊方法,因此请查看该类型,至少在Python 3中是这样的:

>>> 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

  

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

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

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

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

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

对于Python 2,dir() implementation is more elaborate,实际上也委托给其他函数!对于函数对象,它委托给_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()递归地将类层次结构属性合并到最终结果中。

答案 1 :(得分:1)

您正在查看的代码来自最新的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);
}

要在Python 3中实现object.__dir__,请参阅Objects / typeobject.c中的object___dir___impl