diff options
-rw-r--r-- | Include/object.h | 2 | ||||
-rw-r--r-- | Lib/inspect.py | 17 | ||||
-rw-r--r-- | Misc/NEWS | 17 | ||||
-rw-r--r-- | Objects/typeobject.c | 64 |
4 files changed, 33 insertions, 67 deletions
diff --git a/Include/object.h b/Include/object.h index a943c00..c565fbe 100644 --- a/Include/object.h +++ b/Include/object.h @@ -288,7 +288,7 @@ typedef struct _typeobject { inquiry tp_is_gc; /* For PyObject_IS_GC */ PyObject *tp_bases; PyObject *tp_mro; /* method resolution order */ - PyObject *tp_defined; + PyObject *tp_cache; PyObject *tp_subclasses; PyObject *tp_weaklist; diff --git a/Lib/inspect.py b/Lib/inspect.py index c5c6709..e55edca 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -200,24 +200,9 @@ def classify_class_attrs(cls): obj = getattr(cls, name) # Figure out where it was defined. - # A complication: static classes in 2.2 copy dict entries from - # bases into derived classes, so it's not enough just to look for - # "the first" class with the name in its dict. OTOH: - # 1. Some-- but not all --methods in 2.2 come with an __objclass__ - # attr that answers the question directly. - # 2. Some-- but not all --classes in 2.2 have a __defined__ dict - # saying which names were defined by the class. homecls = getattr(obj, "__objclass__", None) if homecls is None: - # Try __defined__. - for base in mro: - if hasattr(base, "__defined__"): - if name in base.__defined__: - homecls = base - break - if homecls is None: - # Last chance (and first chance for classic classes): search - # the dicts. + # search the dicts. for base in mro: if name in base.__dict__: homecls = base @@ -4,15 +4,14 @@ Release date: 28-Sep-2100 Type/class unification and new-style classes -- New-style classes are now dynamic by default. Previous, they were - static (meaning class attributes could not be assigned to) and - dynamic classes had to be requested by adding __dynamic__ = 1 to the - body of the class or to the module. Static classes are faster than - dynamic classes, but dynamic classes are now at most 50% slower than - static classes; previously, they could be up to 10x slower. (This - was accomplished by making dynamic classes faster, not by making - static classes slower. :-) Note that according to one benchmark, - static classes are about the same speed as classic classes. +- New-style classes are now always dynamic (except for built-in and + extension types). There was no longer a performance penalty, and I + no longer see another reason to keep this baggage around. One relic + remains: the __dict__ or a new-style class is a read-only proxy. + You must set the class's attribute to modify. As a consequence, the + __defined__ attribute of new-style types no longer exists, for lack + of need: there is once again only one __dict__ (although in the + future a __cache__ may be resurrected in its place). - C.__doc__ now works as expected for new-style classes (in 2.2a4 it always returned None, even when there was a class docstring). diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 8a78e69..901d026 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -44,7 +44,7 @@ type_module(PyTypeObject *type, void *context) (int)(s - type->tp_name)); if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) return PyString_FromString("__builtin__"); - mod = PyDict_GetItemString(type->tp_defined, "__module__"); + mod = PyDict_GetItemString(type->tp_dict, "__module__"); if (mod != NULL && PyString_Check(mod)) { Py_INCREF(mod); return mod; @@ -80,21 +80,10 @@ type_dict(PyTypeObject *type, void *context) return PyDictProxy_New(type->tp_dict); } -static PyObject * -type_defined(PyTypeObject *type, void *context) -{ - if (type->tp_defined == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - return PyDictProxy_New(type->tp_defined); -} - PyGetSetDef type_getsets[] = { {"__name__", (getter)type_name, NULL, NULL}, {"__module__", (getter)type_module, (setter)type_set_module, NULL}, {"__dict__", (getter)type_dict, NULL, NULL}, - {"__defined__", (getter)type_defined, NULL, NULL}, {0} }; @@ -838,8 +827,8 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) Py_INCREF(base); type->tp_base = base; - /* Initialize tp_defined from passed-in dict */ - type->tp_defined = dict = PyDict_Copy(dict); + /* Initialize tp_dict from passed-in dict */ + type->tp_dict = dict = PyDict_Copy(dict); if (dict == NULL) { Py_DECREF(type); return NULL; @@ -973,14 +962,14 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) int i, n; PyObject *mro, *res, *dict; - /* Look in tp_defined of types in MRO */ + /* Look in tp_dict of types in MRO */ mro = type->tp_mro; assert(PyTuple_Check(mro)); n = PyTuple_GET_SIZE(mro); for (i = 0; i < n; i++) { type = (PyTypeObject *) PyTuple_GET_ITEM(mro, i); assert(PyType_Check(type)); - dict = type->tp_defined; + dict = type->tp_dict; assert(dict && PyDict_Check(dict)); res = PyDict_GetItem(dict, name); if (res != NULL) @@ -1014,7 +1003,7 @@ type_getattro(PyTypeObject *type, PyObject *name) (PyObject *)type, (PyObject *)metatype); } - /* Look in tp_defined of this type and its bases */ + /* Look in tp_dict of this type and its bases */ res = _PyType_Lookup(type, name); if (res != NULL) { f = res->ob_type->tp_descr_get; @@ -1070,7 +1059,7 @@ type_dealloc(PyTypeObject *type) Py_XDECREF(type->tp_dict); Py_XDECREF(type->tp_bases); Py_XDECREF(type->tp_mro); - Py_XDECREF(type->tp_defined); + Py_XDECREF(type->tp_cache); Py_XDECREF(type->tp_subclasses); Py_XDECREF(et->name); Py_XDECREF(et->slots); @@ -1136,7 +1125,7 @@ type_traverse(PyTypeObject *type, visitproc visit, void *arg) } VISIT(type->tp_dict); - VISIT(type->tp_defined); + VISIT(type->tp_cache); VISIT(type->tp_mro); VISIT(type->tp_bases); VISIT(type->tp_base); @@ -1167,7 +1156,7 @@ type_clear(PyTypeObject *type) } CLEAR(type->tp_dict); - CLEAR(type->tp_defined); + CLEAR(type->tp_cache); CLEAR(type->tp_mro); CLEAR(type->tp_bases); CLEAR(type->tp_base); @@ -1455,7 +1444,7 @@ PyTypeObject PyBaseObject_Type = { static int add_methods(PyTypeObject *type, PyMethodDef *meth) { - PyObject *dict = type->tp_defined; + PyObject *dict = type->tp_dict; for (; meth->ml_name != NULL; meth++) { PyObject *descr; @@ -1474,7 +1463,7 @@ add_methods(PyTypeObject *type, PyMethodDef *meth) static int add_members(PyTypeObject *type, PyMemberDef *memb) { - PyObject *dict = type->tp_defined; + PyObject *dict = type->tp_dict; for (; memb->name != NULL; memb++) { PyObject *descr; @@ -1493,7 +1482,7 @@ add_members(PyTypeObject *type, PyMemberDef *memb) static int add_getset(PyTypeObject *type, PyGetSetDef *gsp) { - PyObject *dict = type->tp_defined; + PyObject *dict = type->tp_dict; for (; gsp->name != NULL; gsp++) { PyObject *descr; @@ -1746,7 +1735,6 @@ PyType_Ready(PyTypeObject *type) return 0; } assert((type->tp_flags & Py_TPFLAGS_READYING) == 0); - assert(type->tp_dict == NULL); type->tp_flags |= Py_TPFLAGS_READYING; @@ -1773,16 +1761,16 @@ PyType_Ready(PyTypeObject *type) goto error; } - /* Initialize tp_defined */ - dict = type->tp_defined; + /* Initialize tp_dict */ + dict = type->tp_dict; if (dict == NULL) { dict = PyDict_New(); if (dict == NULL) goto error; - type->tp_defined = dict; + type->tp_dict = dict; } - /* Add type-specific descriptors to tp_defined */ + /* Add type-specific descriptors to tp_dict */ if (add_operators(type) < 0) goto error; if (type->tp_methods != NULL) { @@ -1798,12 +1786,6 @@ PyType_Ready(PyTypeObject *type) goto error; } - /* Temporarily make tp_dict the same object as tp_defined. - (This is needed to call mro(), and can stay this way for - dynamic types). */ - Py_INCREF(type->tp_defined); - type->tp_dict = type->tp_defined; - /* Calculate method resolution order */ if (mro_internal(type) < 0) { goto error; @@ -2676,18 +2658,18 @@ add_tp_new_wrapper(PyTypeObject *type) { PyObject *func; - if (PyDict_GetItemString(type->tp_defined, "__new__") != NULL) + if (PyDict_GetItemString(type->tp_dict, "__new__") != NULL) return 0; func = PyCFunction_New(tp_new_methoddef, (PyObject *)type); if (func == NULL) return -1; - return PyDict_SetItemString(type->tp_defined, "__new__", func); + return PyDict_SetItemString(type->tp_dict, "__new__", func); } static int add_wrappers(PyTypeObject *type, struct wrapperbase *wraps, void *wrapped) { - PyObject *dict = type->tp_defined; + PyObject *dict = type->tp_dict; for (; wraps->name != NULL; wraps++) { PyObject *descr; @@ -2706,14 +2688,14 @@ add_wrappers(PyTypeObject *type, struct wrapperbase *wraps, void *wrapped) /* This function is called by PyType_Ready() to populate the type's dictionary with method descriptors for function slots. For each function slot (like tp_repr) that's defined in the type, one or - more corresponding descriptors are added in the type's tp_defined + more corresponding descriptors are added in the type's tp_dict dictionary under the appropriate name (like __repr__). Some function slots cause more than one descriptor to be added (for example, the nb_add slot adds both __add__ and __radd__ descriptors) and some function slots compete for the same descriptor (for example both sq_item and mp_subscript generate a __getitem__ descriptor). This only adds new descriptors and - doesn't overwrite entries in tp_defined that were previously + doesn't overwrite entries in tp_dict that were previously defined. The descriptors contain a reference to the C function they must call, so that it's safe if they are copied into a subtype's __dict__ and the subtype has a different C function in @@ -3942,7 +3924,7 @@ fixup_slot_dispatchers(PyTypeObject *type) base = (PyTypeObject *)PyTuple_GET_ITEM(mro, i); assert(PyType_Check(base)); descr = PyDict_GetItem( - base->tp_defined, p->name_strobj); + base->tp_dict, p->name_strobj); if (descr != NULL) break; } @@ -4055,7 +4037,7 @@ super_getattro(PyObject *self, PyObject *name) tmp = PyTuple_GET_ITEM(mro, i); assert(PyType_Check(tmp)); res = PyDict_GetItem( - ((PyTypeObject *)tmp)->tp_defined, name); + ((PyTypeObject *)tmp)->tp_dict, name); if (res != NULL) { Py_INCREF(res); f = res->ob_type->tp_descr_get; |