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.
This commit is contained in:
Guido van Rossum 2001-10-15 21:05:10 +00:00
parent f118cb1d6f
commit 2f3ca6eeb6
3 changed files with 42 additions and 157 deletions

View File

@ -432,9 +432,6 @@ given type object has a specified feature.
/* Set if the type allows subclassing */ /* Set if the type allows subclassing */
#define Py_TPFLAGS_BASETYPE (1L<<10) #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 */ /* Set if the type is 'ready' -- fully initialized */
#define Py_TPFLAGS_READY (1L<<12) #define Py_TPFLAGS_READY (1L<<12)

View File

@ -17,6 +17,8 @@ def testunop(a, res, expr="len(a)", meth="__len__"):
vereq(eval(expr, dict), res) vereq(eval(expr, dict), res)
t = type(a) t = type(a)
m = getattr(t, meth) m = getattr(t, meth)
while meth not in t.__dict__:
t = t.__bases__[0]
vereq(m, t.__dict__[meth]) vereq(m, t.__dict__[meth])
vereq(m(a), res) vereq(m(a), res)
bm = getattr(a, meth) bm = getattr(a, meth)
@ -28,6 +30,8 @@ def testbinop(a, b, res, expr="a+b", meth="__add__"):
vereq(eval(expr, dict), res) vereq(eval(expr, dict), res)
t = type(a) t = type(a)
m = getattr(t, meth) m = getattr(t, meth)
while meth not in t.__dict__:
t = t.__bases__[0]
vereq(m, t.__dict__[meth]) vereq(m, t.__dict__[meth])
vereq(m(a, b), res) vereq(m(a, b), res)
bm = getattr(a, meth) 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) vereq(eval(expr, dict), res)
t = type(a) t = type(a)
m = getattr(t, meth) m = getattr(t, meth)
while meth not in t.__dict__:
t = t.__bases__[0]
vereq(m, t.__dict__[meth]) vereq(m, t.__dict__[meth])
vereq(m(a, b, c), res) vereq(m(a, b, c), res)
bm = getattr(a, meth) bm = getattr(a, meth)
@ -51,6 +57,8 @@ def testsetop(a, b, res, stmt="a+=b", meth="__iadd__"):
vereq(dict['a'], res) vereq(dict['a'], res)
t = type(a) t = type(a)
m = getattr(t, meth) m = getattr(t, meth)
while meth not in t.__dict__:
t = t.__bases__[0]
vereq(m, t.__dict__[meth]) vereq(m, t.__dict__[meth])
dict['a'] = deepcopy(a) dict['a'] = deepcopy(a)
m(dict['a'], b) m(dict['a'], b)
@ -67,6 +75,8 @@ def testset2op(a, b, c, res, stmt="a[b]=c", meth="__setitem__"):
vereq(dict['a'], res) vereq(dict['a'], res)
t = type(a) t = type(a)
m = getattr(t, meth) m = getattr(t, meth)
while meth not in t.__dict__:
t = t.__bases__[0]
vereq(m, t.__dict__[meth]) vereq(m, t.__dict__[meth])
dict['a'] = deepcopy(a) dict['a'] = deepcopy(a)
m(dict['a'], b, c) 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 exec stmt in dict
vereq(dict['a'], res) vereq(dict['a'], res)
t = type(a) t = type(a)
while meth not in t.__dict__:
t = t.__bases__[0]
m = getattr(t, meth) m = getattr(t, meth)
vereq(m, t.__dict__[meth]) vereq(m, t.__dict__[meth])
dict['a'] = deepcopy(a) dict['a'] = deepcopy(a)
@ -104,23 +116,19 @@ class Classic2:
class NewStatic(object): class NewStatic(object):
"Another docstring." "Another docstring."
__dynamic__ = 0
vereq(NewStatic.__doc__, "Another docstring.") vereq(NewStatic.__doc__, "Another docstring.")
vereq(NewStatic.__dict__['__doc__'], "Another docstring.") vereq(NewStatic.__dict__['__doc__'], "Another docstring.")
class NewStatic2(object): class NewStatic2(object):
__dynamic__ = 0
pass pass
verify(NewStatic2.__doc__ is None) verify(NewStatic2.__doc__ is None)
class NewDynamic(object): class NewDynamic(object):
"Another docstring." "Another docstring."
__dynamic__ = 1
vereq(NewDynamic.__doc__, "Another docstring.") vereq(NewDynamic.__doc__, "Another docstring.")
vereq(NewDynamic.__dict__['__doc__'], "Another docstring.") vereq(NewDynamic.__dict__['__doc__'], "Another docstring.")
class NewDynamic2(object): class NewDynamic2(object):
__dynamic__ = 1
pass pass
verify(NewDynamic2.__doc__ is None) verify(NewDynamic2.__doc__ is None)
@ -628,7 +636,6 @@ class autosuper(type):
# Automatically add __super to the class # Automatically add __super to the class
# This trick only works for dynamic classes # This trick only works for dynamic classes
def __new__(metaclass, name, bases, dict): def __new__(metaclass, name, bases, dict):
assert dict.get("__dynamic__", 1)
cls = super(autosuper, metaclass).__new__(metaclass, cls = super(autosuper, metaclass).__new__(metaclass,
name, bases, dict) name, bases, dict)
# Name mangling for __super removes leading underscores # Name mangling for __super removes leading underscores
@ -863,54 +870,21 @@ class C3(object):
vereq(x.c, 3) vereq(x.c, 3)
def dynamics(): def dynamics():
if verbose: print "Testing __dynamic__..." if verbose: print "Testing class attribute propagation..."
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)
class D(object): class D(object):
__dynamic__ = 1
vereq(D.__dynamic__, 1)
class E(D, S):
pass pass
vereq(E.__dynamic__, 1) class E(D):
class F(S, D):
pass pass
vereq(F.__dynamic__, 1) class F(D):
try:
S.foo = 1
except (AttributeError, TypeError):
pass pass
else:
verify(0, "assignment to a static class attribute should be illegal")
D.foo = 1 D.foo = 1
vereq(D.foo, 1) vereq(D.foo, 1)
# Test that dynamic attributes are inherited # Test that dynamic attributes are inherited
vereq(E.foo, 1) vereq(E.foo, 1)
vereq(F.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 # Test dynamic instances
class C(object): class C(object):
__dynamic__ = 1 pass
# 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
a = C() a = C()
verify(not hasattr(a, "foobar")) verify(not hasattr(a, "foobar"))
C.foobar = 2 C.foobar = 2
@ -951,7 +925,7 @@ class D(C):
# Test handling of int*seq and seq*int # Test handling of int*seq and seq*int
class I(int): class I(int):
__dynamic__ = 1 # XXX why? pass
vereq("a"*I(2), "aa") vereq("a"*I(2), "aa")
vereq(I(2)*"a", "aa") vereq(I(2)*"a", "aa")
vereq(2*I(3), 6) vereq(2*I(3), 6)
@ -960,7 +934,7 @@ class I(int):
# Test handling of long*seq and seq*long # Test handling of long*seq and seq*long
class L(long): class L(long):
__dynamic__ = 1 # XXX why? pass
vereq("a"*L(2L), "aa") vereq("a"*L(2L), "aa")
vereq(L(2L)*"a", "aa") vereq(L(2L)*"a", "aa")
vereq(2*L(3), 6) vereq(2*L(3), 6)
@ -969,7 +943,7 @@ class L(long):
# Test comparison of classes with dynamic metaclasses # Test comparison of classes with dynamic metaclasses
class dynamicmetaclass(type): class dynamicmetaclass(type):
__dynamic__ = 1 # XXX ??? pass
class someclass: class someclass:
__metaclass__ = dynamicmetaclass __metaclass__ = dynamicmetaclass
verify(someclass != object) verify(someclass != object)
@ -1255,7 +1229,6 @@ def __getitem__(self, i):
verify(10 not in c1) verify(10 not in c1)
# Test the default behavior for dynamic classes # Test the default behavior for dynamic classes
class D(object): class D(object):
__dynamic__ = 1 # XXX why?
def __getitem__(self, i): def __getitem__(self, i):
if 0 <= i < 10: return i if 0 <= i < 10: return i
raise IndexError raise IndexError
@ -1318,7 +1291,6 @@ def __contains__(self, value):
verify(10 not in p10) verify(10 not in p10)
# Test overridden behavior for dynamic classes # Test overridden behavior for dynamic classes
class DProxy(object): class DProxy(object):
__dynamic__ = 1
def __init__(self, x): def __init__(self, x):
self.x = x self.x = x
def __nonzero__(self): def __nonzero__(self):
@ -1469,7 +1441,6 @@ def meth(self, a):
vereq(B().meth(2), "B(2)A(2)") vereq(B().meth(2), "B(2)A(2)")
class C(A): class C(A):
__dynamic__ = 1
def meth(self, a): def meth(self, a):
return "C(%r)" % a + self.__super.meth(a) return "C(%r)" % a + self.__super.meth(a)
C._C__super = super(C) C._C__super = super(C)
@ -1565,7 +1536,6 @@ def __repr__(self):
verify((+a).__class__ is float) verify((+a).__class__ is float)
class madcomplex(complex): class madcomplex(complex):
__dynamic__ = 0 # XXX Shouldn't be necessary
def __repr__(self): def __repr__(self):
return "%.17gj%+.17g" % (self.imag, self.real) return "%.17gj%+.17g" % (self.imag, self.real)
a = madcomplex(-3, 4) a = madcomplex(-3, 4)
@ -1967,12 +1937,11 @@ def rich_comparisons():
if verbose: if verbose:
print "Testing rich comparisons..." print "Testing rich comparisons..."
class Z(complex): class Z(complex):
__dynamic__ = 0 pass
z = Z(1) z = Z(1)
vereq(z, 1+0j) vereq(z, 1+0j)
vereq(1+0j, z) vereq(1+0j, z)
class ZZ(complex): class ZZ(complex):
__dynamic__ = 0
def __eq__(self, other): def __eq__(self, other):
try: try:
return abs(self - other) <= 1e-6 return abs(self - other) <= 1e-6
@ -2059,8 +2028,7 @@ class F(float): pass
coerce(0, F(0)) coerce(0, F(0))
coerce(0L, F(0)) coerce(0L, F(0))
coerce(0., F(0)) coerce(0., F(0))
class C(complex): class C(complex): pass
__dynamic__ = 0
coerce(C(0), 0) coerce(C(0), 0)
coerce(C(0), 0L) coerce(C(0), 0L)
coerce(C(0), 0.) coerce(C(0), 0.)

View File

@ -56,7 +56,7 @@ type_module(PyTypeObject *type, void *context)
static int static int
type_set_module(PyTypeObject *type, PyObject *value, void *context) 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, '.')) { strrchr(type->tp_name, '.')) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"can't set %s.__module__", type->tp_name); "can't set %s.__module__", type->tp_name);
@ -77,10 +77,6 @@ type_dict(PyTypeObject *type, void *context)
Py_INCREF(Py_None); Py_INCREF(Py_None);
return 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); return PyDictProxy_New(type->tp_dict);
} }
@ -91,29 +87,14 @@ type_defined(PyTypeObject *type, void *context)
Py_INCREF(Py_None); Py_INCREF(Py_None);
return 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); 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[] = { PyGetSetDef type_getsets[] = {
{"__name__", (getter)type_name, NULL, NULL}, {"__name__", (getter)type_name, NULL, NULL},
{"__module__", (getter)type_module, (setter)type_set_module, NULL}, {"__module__", (getter)type_module, (setter)type_set_module, NULL},
{"__dict__", (getter)type_dict, NULL, NULL}, {"__dict__", (getter)type_dict, NULL, NULL},
{"__defined__", (getter)type_defined, NULL, NULL}, {"__defined__", (getter)type_defined, NULL, NULL},
{"__dynamic__", (getter)type_dynamic, NULL, NULL},
{0} {0}
}; };
@ -711,7 +692,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
PyTypeObject *type, *base, *tmptype, *winner; PyTypeObject *type, *base, *tmptype, *winner;
etype *et; etype *et;
PyMemberDef *mp; 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 */ /* Special case: type(x) should return x->ob_type */
if (metatype == &PyType_Type && if (metatype == &PyType_Type &&
@ -777,38 +758,6 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
return NULL; 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 */ /* Check for a __slots__ sequence variable in dict, and count it */
slots = PyDict_GetItemString(dict, "__slots__"); slots = PyDict_GetItemString(dict, "__slots__");
nslots = 0; nslots = 0;
@ -868,8 +817,6 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
/* Initialize tp_flags */ /* Initialize tp_flags */
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE | type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE |
Py_TPFLAGS_BASETYPE; Py_TPFLAGS_BASETYPE;
if (dynamic)
type->tp_flags |= Py_TPFLAGS_DYNAMICTYPE;
if (base->tp_flags & Py_TPFLAGS_HAVE_GC) if (base->tp_flags & Py_TPFLAGS_HAVE_GC)
type->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; int i, n;
PyObject *mro, *res, *dict; PyObject *mro, *res, *dict;
/* For static types, look in tp_dict */ /* Look in tp_defined of types in MRO */
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 */
mro = type->tp_mro; mro = type->tp_mro;
assert(PyTuple_Check(mro)); assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro); n = PyTuple_GET_SIZE(mro);
@ -1104,13 +1044,16 @@ type_getattro(PyTypeObject *type, PyObject *name)
static int static int
type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
{ {
if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) { if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0) PyErr_Format(
return -1; PyExc_TypeError,
return update_slot(type, name); "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"); if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
return -1; return -1;
return update_slot(type, name);
} }
static void static void
@ -1794,7 +1737,7 @@ staticforward int add_subclass(PyTypeObject *base, PyTypeObject *type);
int int
PyType_Ready(PyTypeObject *type) PyType_Ready(PyTypeObject *type)
{ {
PyObject *dict, *bases, *x; PyObject *dict, *bases;
PyTypeObject *base; PyTypeObject *base;
int i, n; int i, n;
@ -1871,37 +1814,14 @@ PyType_Ready(PyTypeObject *type)
inherit_special(type, type->tp_base); inherit_special(type, type->tp_base);
/* Initialize tp_dict properly */ /* Initialize tp_dict properly */
if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) { bases = type->tp_mro;
/* For a static type, tp_dict is the consolidation assert(bases != NULL);
of the tp_defined of its bases in MRO. */ assert(PyTuple_Check(bases));
Py_DECREF(type->tp_dict); n = PyTuple_GET_SIZE(bases);
type->tp_dict = PyDict_Copy(type->tp_defined); for (i = 1; i < n; i++) {
if (type->tp_dict == NULL) base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
goto error; assert(PyType_Check(base));
bases = type->tp_mro; inherit_slots(type, base);
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);
}
} }
/* Some more special stuff */ /* Some more special stuff */