代码之家  ›  专栏  ›  技术社区  ›  max

子类方法是如何在CPython中实现的?

  •  5
  • max  · 技术社区  · 8 年前

    文件说:

    每个类都保留对其直接子类的弱引用列表。此方法返回所有仍然有效的引用的列表。

    但是,每个类如何首先获得对其子类的弱引用列表?换句话说,当我创建

    class B(A):
      pass
    

    怎么做 A 发现 B 只是子类化了它?这种机制是否足够健壮,能够在边缘情况下生存(自定义元类、分配到 __bases__ 等等)?

    1 回复  |  直到 8 年前
        1
  •  6
  •   user2357112    8 年前

    作为新类初始化的一部分,将该类的弱引用添加到 tp_subclasses 每个基类的成员。您可以在中的Python源代码中看到这一点 Objects/typeobject.c :

    int
    PyType_Ready(PyTypeObject *type)
    {
        ...
        /* Link into each base class's list of subclasses */
        bases = type->tp_bases;
        n = PyTuple_GET_SIZE(bases);
        for (i = 0; i < n; i++) {
            PyObject *b = PyTuple_GET_ITEM(bases, i);
            if (PyType_Check(b) &&
                add_subclass((PyTypeObject *)b, type) < 0)
                goto error;
        }
        ...
    }
    
    static int
    add_subclass(PyTypeObject *base, PyTypeObject *type)
    {
        int result = -1;
        PyObject *dict, *key, *newobj;
    
        dict = base->tp_subclasses;
        if (dict == NULL) {
            base->tp_subclasses = dict = PyDict_New();
            if (dict == NULL)
                return -1;
        }
        assert(PyDict_CheckExact(dict));
        key = PyLong_FromVoidPtr((void *) type);
        if (key == NULL)
            return -1;
        newobj = PyWeakref_NewRef((PyObject *)type, NULL);
        if (newobj != NULL) {
            result = PyDict_SetItem(dict, key, newobj);
            Py_DECREF(newobj);
        }
        Py_DECREF(key);
        return result;
    }
    

    这个 setter 对于 __bases__ 还更新每个旧基和新基的子类列表:

    static int
    type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context)
    {
        ...
        if (type->tp_bases == new_bases) {
            /* any base that was in __bases__ but now isn't, we
               need to remove |type| from its tp_subclasses.
               conversely, any class now in __bases__ that wasn't
               needs to have |type| added to its subclasses. */
    
            /* for now, sod that: just remove from all old_bases,
               add to all new_bases */
            remove_all_subclasses(type, old_bases);
            res = add_all_subclasses(type, new_bases);
            update_all_slots(type);
        }
        ...
    }
    

    注意,如果元类做了一些事情来定制子类关系的含义, __subclasses__ 不会反映这一点。例如 issubclass(list, collections.abc.Iterable) True 但是 list 不会在搜索中显示 __子类__ collections.abc.Iterable .