How different is type.__setattr__ from object.__setattr__?

后端 未结 1 1200
谎友^
谎友^ 2021-02-14 12:37

type.__setattr__ is used for classes, basically instances of metaclasses. object.__setattr__ on the other hand, is used for instances of classes. This

1条回答
  •  忘了有多久
    2021-02-14 13:07

    type.__setattr__ has a check to prevent setting attributes on types like int, and it does a bunch of invisible cleanup that isn't needed for normal objects.


    Let's take a look under the hood! Here's type.__setattr__:

    static int
    type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
    {
        if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
            PyErr_Format(
                PyExc_TypeError,
                "can't set attributes of built-in/extension type '%s'",
                type->tp_name);
            return -1;
        }
        if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
            return -1;
        return update_slot(type, name);
    }
    

    and if we examine PyBaseObject_Type, we see it uses PyObject_GenericSetAttr for its __setattr__, the same call that appears halfway through type_setattro.

    Thus, type.__setattr__ is like object.__setattr__, but with some additional handling wrapped around it.

    First, the if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) check prohibits attribute assignment on types written in C, like int or numpy.array, because assigning attributes on those can seriously screw up the Python internals in ways someone unfamiliar with the C API might not expect.

    Second, after the PyObject_GenericSetAttr call updates the type's dict or calls an appropriate descriptor from the metaclass, update_slot fixes up any slots affected by the attribute assignment. These slots are C-level function pointers that implement functionality like instance allocation, in checks, +, deallocation, etc. Most of them have corresponding Python-level methods, like __contains__ or __add__, and if one of those Python-level methods is reassigned, the corresponding slot (or slots) have to be updated, too. update_slot also updates slots on all descendants of the class, and it invalidates entries in an internal attribute cache used for type object attributes.

    0 讨论(0)
提交回复
热议问题