From 2f3ca6eeb6eeebcfa038cd52aca5fecfa74dbd28 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 15 Oct 2001 21:05:10 +0000 Subject: Completely get rid of __dynamic__ and the corresponding Py_TPFLAGS_DYNAMICTYPE bit. There is no longer a performance benefit, and I don't really see the use case any more. --- Include/object.h | 3 -- Lib/test/test_descr.py | 74 +++++++++--------------------- Objects/typeobject.c | 122 +++++++++---------------------------------------- 3 files changed, 42 insertions(+), 157 deletions(-) diff --git a/Include/object.h b/Include/object.h index 8620766..a943c00 100644 --- a/Include/object.h +++ b/Include/object.h @@ -432,9 +432,6 @@ given type object has a specified feature. /* Set if the type allows subclassing */ #define Py_TPFLAGS_BASETYPE (1L<<10) -/* Set if the type's __dict__ may change */ -#define Py_TPFLAGS_DYNAMICTYPE (1L<<11) - /* Set if the type is 'ready' -- fully initialized */ #define Py_TPFLAGS_READY (1L<<12) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index e5ee591..a15e7a0 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -17,6 +17,8 @@ def testunop(a, res, expr="len(a)", meth="__len__"): vereq(eval(expr, dict), res) t = type(a) m = getattr(t, meth) + while meth not in t.__dict__: + t = t.__bases__[0] vereq(m, t.__dict__[meth]) vereq(m(a), res) bm = getattr(a, meth) @@ -28,6 +30,8 @@ def testbinop(a, b, res, expr="a+b", meth="__add__"): vereq(eval(expr, dict), res) t = type(a) m = getattr(t, meth) + while meth not in t.__dict__: + t = t.__bases__[0] vereq(m, t.__dict__[meth]) vereq(m(a, b), res) bm = getattr(a, meth) @@ -39,6 +43,8 @@ def testternop(a, b, c, res, expr="a[b:c]", meth="__getslice__"): vereq(eval(expr, dict), res) t = type(a) m = getattr(t, meth) + while meth not in t.__dict__: + t = t.__bases__[0] vereq(m, t.__dict__[meth]) vereq(m(a, b, c), res) bm = getattr(a, meth) @@ -51,6 +57,8 @@ def testsetop(a, b, res, stmt="a+=b", meth="__iadd__"): vereq(dict['a'], res) t = type(a) m = getattr(t, meth) + while meth not in t.__dict__: + t = t.__bases__[0] vereq(m, t.__dict__[meth]) dict['a'] = deepcopy(a) m(dict['a'], b) @@ -67,6 +75,8 @@ def testset2op(a, b, c, res, stmt="a[b]=c", meth="__setitem__"): vereq(dict['a'], res) t = type(a) m = getattr(t, meth) + while meth not in t.__dict__: + t = t.__bases__[0] vereq(m, t.__dict__[meth]) dict['a'] = deepcopy(a) m(dict['a'], b, c) @@ -82,6 +92,8 @@ def testset3op(a, b, c, d, res, stmt="a[b:c]=d", meth="__setslice__"): exec stmt in dict vereq(dict['a'], res) t = type(a) + while meth not in t.__dict__: + t = t.__bases__[0] m = getattr(t, meth) vereq(m, t.__dict__[meth]) dict['a'] = deepcopy(a) @@ -104,23 +116,19 @@ def class_docstrings(): class NewStatic(object): "Another docstring." - __dynamic__ = 0 vereq(NewStatic.__doc__, "Another docstring.") vereq(NewStatic.__dict__['__doc__'], "Another docstring.") class NewStatic2(object): - __dynamic__ = 0 pass verify(NewStatic2.__doc__ is None) class NewDynamic(object): "Another docstring." - __dynamic__ = 1 vereq(NewDynamic.__doc__, "Another docstring.") vereq(NewDynamic.__dict__['__doc__'], "Another docstring.") class NewDynamic2(object): - __dynamic__ = 1 pass verify(NewDynamic2.__doc__ is None) @@ -628,7 +636,6 @@ def metaclass(): # Automatically add __super to the class # This trick only works for dynamic classes def __new__(metaclass, name, bases, dict): - assert dict.get("__dynamic__", 1) cls = super(autosuper, metaclass).__new__(metaclass, name, bases, dict) # Name mangling for __super removes leading underscores @@ -863,54 +870,21 @@ def slots(): vereq(x.c, 3) def dynamics(): - if verbose: print "Testing __dynamic__..." - vereq(object.__dynamic__, 0) - vereq(list.__dynamic__, 0) - class S1: - __metaclass__ = type - __dynamic__ = 0 - vereq(S1.__dynamic__, 0) - class S(object): - __dynamic__ = 0 - vereq(S.__dynamic__, 0) + if verbose: print "Testing class attribute propagation..." class D(object): - __dynamic__ = 1 - vereq(D.__dynamic__, 1) - class E(D, S): pass - vereq(E.__dynamic__, 1) - class F(S, D): + class E(D): pass - vereq(F.__dynamic__, 1) - try: - S.foo = 1 - except (AttributeError, TypeError): + class F(D): pass - else: - verify(0, "assignment to a static class attribute should be illegal") D.foo = 1 vereq(D.foo, 1) # Test that dynamic attributes are inherited vereq(E.foo, 1) vereq(F.foo, 1) - class SS(D): - __dynamic__ = 0 - vereq(SS.__dynamic__, 0) - vereq(SS.foo, 1) - try: - SS.foo = 1 - except (AttributeError, TypeError): - pass - else: - verify(0, "assignment to SS.foo should be illegal") # Test dynamic instances class C(object): - __dynamic__ = 1 - # XXX Ideally the following def shouldn't be necessary, - # but it's too much of a performance burden. - # See XXX comment in slot_tp_getattr_hook. - def __getattr__(self, name): - raise AttributeError, name + pass a = C() verify(not hasattr(a, "foobar")) C.foobar = 2 @@ -951,7 +925,7 @@ def dynamics(): # Test handling of int*seq and seq*int class I(int): - __dynamic__ = 1 # XXX why? + pass vereq("a"*I(2), "aa") vereq(I(2)*"a", "aa") vereq(2*I(3), 6) @@ -960,7 +934,7 @@ def dynamics(): # Test handling of long*seq and seq*long class L(long): - __dynamic__ = 1 # XXX why? + pass vereq("a"*L(2L), "aa") vereq(L(2L)*"a", "aa") vereq(2*L(3), 6) @@ -969,7 +943,7 @@ def dynamics(): # Test comparison of classes with dynamic metaclasses class dynamicmetaclass(type): - __dynamic__ = 1 # XXX ??? + pass class someclass: __metaclass__ = dynamicmetaclass verify(someclass != object) @@ -1255,7 +1229,6 @@ def specials(): verify(10 not in c1) # Test the default behavior for dynamic classes class D(object): - __dynamic__ = 1 # XXX why? def __getitem__(self, i): if 0 <= i < 10: return i raise IndexError @@ -1318,7 +1291,6 @@ def specials(): verify(10 not in p10) # Test overridden behavior for dynamic classes class DProxy(object): - __dynamic__ = 1 def __init__(self, x): self.x = x def __nonzero__(self): @@ -1469,7 +1441,6 @@ def supers(): vereq(B().meth(2), "B(2)A(2)") class C(A): - __dynamic__ = 1 def meth(self, a): return "C(%r)" % a + self.__super.meth(a) C._C__super = super(C) @@ -1565,7 +1536,6 @@ def inherits(): verify((+a).__class__ is float) class madcomplex(complex): - __dynamic__ = 0 # XXX Shouldn't be necessary def __repr__(self): return "%.17gj%+.17g" % (self.imag, self.real) a = madcomplex(-3, 4) @@ -1967,12 +1937,11 @@ def rich_comparisons(): if verbose: print "Testing rich comparisons..." class Z(complex): - __dynamic__ = 0 + pass z = Z(1) vereq(z, 1+0j) vereq(1+0j, z) class ZZ(complex): - __dynamic__ = 0 def __eq__(self, other): try: return abs(self - other) <= 1e-6 @@ -2059,8 +2028,7 @@ def coercions(): coerce(0, F(0)) coerce(0L, F(0)) coerce(0., F(0)) - class C(complex): - __dynamic__ = 0 + class C(complex): pass coerce(C(0), 0) coerce(C(0), 0L) coerce(C(0), 0.) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b401abc..8a78e69 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -56,7 +56,7 @@ type_module(PyTypeObject *type, void *context) static int type_set_module(PyTypeObject *type, PyObject *value, void *context) { - if (!(type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) || + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) || strrchr(type->tp_name, '.')) { PyErr_Format(PyExc_TypeError, "can't set %s.__module__", type->tp_name); @@ -77,10 +77,6 @@ type_dict(PyTypeObject *type, void *context) Py_INCREF(Py_None); return Py_None; } - if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) { - Py_INCREF(type->tp_dict); - return type->tp_dict; - } return PyDictProxy_New(type->tp_dict); } @@ -91,29 +87,14 @@ type_defined(PyTypeObject *type, void *context) Py_INCREF(Py_None); return Py_None; } - if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) { - Py_INCREF(type->tp_defined); - return type->tp_defined; - } return PyDictProxy_New(type->tp_defined); } -static PyObject * -type_dynamic(PyTypeObject *type, void *context) -{ - PyObject *res; - - res = (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) ? Py_True : Py_False; - Py_INCREF(res); - return res; -} - 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}, - {"__dynamic__", (getter)type_dynamic, NULL, NULL}, {0} }; @@ -711,7 +692,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) PyTypeObject *type, *base, *tmptype, *winner; etype *et; PyMemberDef *mp; - int i, nbases, nslots, slotoffset, dynamic, add_dict, add_weak; + int i, nbases, nslots, slotoffset, add_dict, add_weak; /* Special case: type(x) should return x->ob_type */ if (metatype == &PyType_Type && @@ -777,38 +758,6 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) return NULL; } - /* Should this be a dynamic class (i.e. modifiable __dict__)? - Look in two places for a variable named __dynamic__: - 1) in the class dict - 2) in the module dict (globals) - The first variable that is an int >= 0 is used. - Otherwise, the default is dynamic. */ - dynamic = -1; /* Not yet determined */ - /* Look in the class */ - tmp = PyDict_GetItemString(dict, "__dynamic__"); - if (tmp != NULL) { - dynamic = PyInt_AsLong(tmp); - if (dynamic < 0) - PyErr_Clear(); - } - if (dynamic < 0) { - /* Look in the module globals */ - tmp = PyEval_GetGlobals(); - if (tmp != NULL) { - tmp = PyDict_GetItemString(tmp, "__dynamic__"); - if (tmp != NULL) { - dynamic = PyInt_AsLong(tmp); - if (dynamic < 0) - PyErr_Clear(); - } - } - } - if (dynamic < 0) { - /* Default to dynamic */ - dynamic = 1; - - } - /* Check for a __slots__ sequence variable in dict, and count it */ slots = PyDict_GetItemString(dict, "__slots__"); nslots = 0; @@ -868,8 +817,6 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) /* Initialize tp_flags */ type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE | Py_TPFLAGS_BASETYPE; - if (dynamic) - type->tp_flags |= Py_TPFLAGS_DYNAMICTYPE; if (base->tp_flags & Py_TPFLAGS_HAVE_GC) type->tp_flags |= Py_TPFLAGS_HAVE_GC; @@ -1026,14 +973,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) int i, n; PyObject *mro, *res, *dict; - /* For static types, look in tp_dict */ - if (!(type->tp_flags & Py_TPFLAGS_DYNAMICTYPE)) { - dict = type->tp_dict; - assert(dict && PyDict_Check(dict)); - return PyDict_GetItem(dict, name); - } - - /* For dynamic types, look in tp_defined of types in MRO */ + /* Look in tp_defined of types in MRO */ mro = type->tp_mro; assert(PyTuple_Check(mro)); n = PyTuple_GET_SIZE(mro); @@ -1104,13 +1044,16 @@ type_getattro(PyTypeObject *type, PyObject *name) static int type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) { - if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) { - if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0) - return -1; - return update_slot(type, name); + 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; } - PyErr_SetString(PyExc_TypeError, "can't set static type attributes"); - return -1; + if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0) + return -1; + return update_slot(type, name); } static void @@ -1794,7 +1737,7 @@ staticforward int add_subclass(PyTypeObject *base, PyTypeObject *type); int PyType_Ready(PyTypeObject *type) { - PyObject *dict, *bases, *x; + PyObject *dict, *bases; PyTypeObject *base; int i, n; @@ -1871,37 +1814,14 @@ PyType_Ready(PyTypeObject *type) inherit_special(type, type->tp_base); /* Initialize tp_dict properly */ - if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) { - /* For a static type, tp_dict is the consolidation - of the tp_defined of its bases in MRO. */ - Py_DECREF(type->tp_dict); - type->tp_dict = PyDict_Copy(type->tp_defined); - if (type->tp_dict == NULL) - goto error; - bases = type->tp_mro; - assert(bases != NULL); - assert(PyTuple_Check(bases)); - n = PyTuple_GET_SIZE(bases); - for (i = 1; i < n; i++) { - base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i); - assert(PyType_Check(base)); - x = base->tp_defined; - if (x != NULL && PyDict_Merge(type->tp_dict, x, 0) < 0) - goto error; - inherit_slots(type, base); - } - } - else { - /* For a dynamic type, we simply inherit the base slots. */ - bases = type->tp_mro; - assert(bases != NULL); - assert(PyTuple_Check(bases)); - n = PyTuple_GET_SIZE(bases); - for (i = 1; i < n; i++) { - base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i); - assert(PyType_Check(base)); - inherit_slots(type, base); - } + bases = type->tp_mro; + assert(bases != NULL); + assert(PyTuple_Check(bases)); + n = PyTuple_GET_SIZE(bases); + for (i = 1; i < n; i++) { + base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i); + assert(PyType_Check(base)); + inherit_slots(type, base); } /* Some more special stuff */ -- cgit v0.12