mirror of https://github.com/python/cpython
Issue #13575: there is only one class type.
This commit is contained in:
parent
9d57481f04
commit
aa6c1d240f
|
@ -36,9 +36,7 @@ continuing through the base classes of ``type(a)`` excluding metaclasses. If the
|
||||||
looked-up value is an object defining one of the descriptor methods, then Python
|
looked-up value is an object defining one of the descriptor methods, then Python
|
||||||
may override the default behavior and invoke the descriptor method instead.
|
may override the default behavior and invoke the descriptor method instead.
|
||||||
Where this occurs in the precedence chain depends on which descriptor methods
|
Where this occurs in the precedence chain depends on which descriptor methods
|
||||||
were defined. Note that descriptors are only invoked for new style objects or
|
were defined.
|
||||||
classes (a class is new style if it inherits from :class:`object` or
|
|
||||||
:class:`type`).
|
|
||||||
|
|
||||||
Descriptors are a powerful, general purpose protocol. They are the mechanism
|
Descriptors are a powerful, general purpose protocol. They are the mechanism
|
||||||
behind properties, methods, static methods, class methods, and :func:`super()`.
|
behind properties, methods, static methods, class methods, and :func:`super()`.
|
||||||
|
@ -89,8 +87,6 @@ of ``obj``. If ``d`` defines the method :meth:`__get__`, then ``d.__get__(obj)`
|
||||||
is invoked according to the precedence rules listed below.
|
is invoked according to the precedence rules listed below.
|
||||||
|
|
||||||
The details of invocation depend on whether ``obj`` is an object or a class.
|
The details of invocation depend on whether ``obj`` is an object or a class.
|
||||||
Either way, descriptors only work for new style objects and classes. A class is
|
|
||||||
new style if it is a subclass of :class:`object`.
|
|
||||||
|
|
||||||
For objects, the machinery is in :meth:`object.__getattribute__` which
|
For objects, the machinery is in :meth:`object.__getattribute__` which
|
||||||
transforms ``b.x`` into ``type(b).__dict__['x'].__get__(b, type(b))``. The
|
transforms ``b.x`` into ``type(b).__dict__['x'].__get__(b, type(b))``. The
|
||||||
|
@ -115,7 +111,6 @@ The important points to remember are:
|
||||||
|
|
||||||
* descriptors are invoked by the :meth:`__getattribute__` method
|
* descriptors are invoked by the :meth:`__getattribute__` method
|
||||||
* overriding :meth:`__getattribute__` prevents automatic descriptor calls
|
* overriding :meth:`__getattribute__` prevents automatic descriptor calls
|
||||||
* :meth:`__getattribute__` is only available with new style classes and objects
|
|
||||||
* :meth:`object.__getattribute__` and :meth:`type.__getattribute__` make
|
* :meth:`object.__getattribute__` and :meth:`type.__getattribute__` make
|
||||||
different calls to :meth:`__get__`.
|
different calls to :meth:`__get__`.
|
||||||
* data descriptors always override instance dictionaries.
|
* data descriptors always override instance dictionaries.
|
||||||
|
@ -128,10 +123,7 @@ and then returns ``A.__dict__['m'].__get__(obj, A)``. If not a descriptor,
|
||||||
``m`` is returned unchanged. If not in the dictionary, ``m`` reverts to a
|
``m`` is returned unchanged. If not in the dictionary, ``m`` reverts to a
|
||||||
search using :meth:`object.__getattribute__`.
|
search using :meth:`object.__getattribute__`.
|
||||||
|
|
||||||
Note, in Python 2.2, ``super(B, obj).m()`` would only invoke :meth:`__get__` if
|
The implementation details are in :c:func:`super_getattro()` in
|
||||||
``m`` was a data descriptor. In Python 2.3, non-data descriptors also get
|
|
||||||
invoked unless an old-style class is involved. The implementation details are
|
|
||||||
in :c:func:`super_getattro()` in
|
|
||||||
`Objects/typeobject.c <http://svn.python.org/view/python/trunk/Objects/typeobject.c?view=markup>`_
|
`Objects/typeobject.c <http://svn.python.org/view/python/trunk/Objects/typeobject.c?view=markup>`_
|
||||||
and a pure Python equivalent can be found in `Guido's Tutorial`_.
|
and a pure Python equivalent can be found in `Guido's Tutorial`_.
|
||||||
|
|
||||||
|
|
|
@ -375,7 +375,7 @@ class _Pickler:
|
||||||
# allowing protocol 0 and 1 to work normally. For this to
|
# allowing protocol 0 and 1 to work normally. For this to
|
||||||
# work, the function returned by __reduce__ should be
|
# work, the function returned by __reduce__ should be
|
||||||
# called __newobj__, and its first argument should be a
|
# called __newobj__, and its first argument should be a
|
||||||
# new-style class. The implementation for __newobj__
|
# class. The implementation for __newobj__
|
||||||
# should be as follows, although pickle has no way to
|
# should be as follows, although pickle has no way to
|
||||||
# verify this:
|
# verify this:
|
||||||
#
|
#
|
||||||
|
|
|
@ -1639,6 +1639,8 @@ opcodes = [
|
||||||
is pushed on the stack.
|
is pushed on the stack.
|
||||||
|
|
||||||
NOTE: checks for __safe_for_unpickling__ went away in Python 2.3.
|
NOTE: checks for __safe_for_unpickling__ went away in Python 2.3.
|
||||||
|
NOTE: the distinction between old-style and new-style classes does
|
||||||
|
not make sense in Python 3.
|
||||||
"""),
|
"""),
|
||||||
|
|
||||||
I(name='OBJ',
|
I(name='OBJ',
|
||||||
|
|
|
@ -15,8 +15,8 @@ have been called before resurrection). At best (and this has been an
|
||||||
historically common bug), tp_clear empties an instance's __dict__, and
|
historically common bug), tp_clear empties an instance's __dict__, and
|
||||||
"impossible" AttributeErrors result. At worst, tp_clear leaves behind an
|
"impossible" AttributeErrors result. At worst, tp_clear leaves behind an
|
||||||
insane object at the C level, and segfaults result (historically, most
|
insane object at the C level, and segfaults result (historically, most
|
||||||
often by setting a new-style class's mro pointer to NULL, after which
|
often by setting a class's mro pointer to NULL, after which attribute
|
||||||
attribute lookups performed by the class can segfault).
|
lookups performed by the class can segfault).
|
||||||
|
|
||||||
OTOH, it's OK to run Python-level code that can't access unreachable
|
OTOH, it's OK to run Python-level code that can't access unreachable
|
||||||
objects, and sometimes that's necessary. The chief example is the callback
|
objects, and sometimes that's necessary. The chief example is the callback
|
||||||
|
@ -119,7 +119,7 @@ isn't easy to stumble into by accident while Python is running, and, indeed,
|
||||||
it took quite a while to dream up failing test cases. Zope3 saw segfaults
|
it took quite a while to dream up failing test cases. Zope3 saw segfaults
|
||||||
during shutdown, during the second call of gc in Py_Finalize, after most
|
during shutdown, during the second call of gc in Py_Finalize, after most
|
||||||
modules had been torn down. That creates many trash cycles (esp. those
|
modules had been torn down. That creates many trash cycles (esp. those
|
||||||
involving new-style classes), making the problem much more likely. Once you
|
involving classes), making the problem much more likely. Once you
|
||||||
know what's required to provoke the problem, though, it's easy to create
|
know what's required to provoke the problem, though, it's easy to create
|
||||||
tests that segfault before shutdown.
|
tests that segfault before shutdown.
|
||||||
|
|
||||||
|
|
|
@ -100,15 +100,13 @@ PyType_Modified(PyTypeObject *type)
|
||||||
static void
|
static void
|
||||||
type_mro_modified(PyTypeObject *type, PyObject *bases) {
|
type_mro_modified(PyTypeObject *type, PyObject *bases) {
|
||||||
/*
|
/*
|
||||||
Check that all base classes or elements of the mro of type are
|
Check that all base classes or elements of the MRO of type are
|
||||||
able to be cached. This function is called after the base
|
able to be cached. This function is called after the base
|
||||||
classes or mro of the type are altered.
|
classes or mro of the type are altered.
|
||||||
|
|
||||||
Unset HAVE_VERSION_TAG and VALID_VERSION_TAG if the type
|
Unset HAVE_VERSION_TAG and VALID_VERSION_TAG if the type
|
||||||
inherits from an old-style class, either directly or if it
|
has a custom MRO that includes a type which is not officially
|
||||||
appears in the MRO of a new-style class. No support either for
|
super type.
|
||||||
custom MROs that include types that are not officially super
|
|
||||||
types.
|
|
||||||
|
|
||||||
Called from mro_internal, which will subsequently be called on
|
Called from mro_internal, which will subsequently be called on
|
||||||
each subclass when their mro is recursively updated.
|
each subclass when their mro is recursively updated.
|
||||||
|
@ -124,11 +122,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
|
||||||
PyObject *b = PyTuple_GET_ITEM(bases, i);
|
PyObject *b = PyTuple_GET_ITEM(bases, i);
|
||||||
PyTypeObject *cls;
|
PyTypeObject *cls;
|
||||||
|
|
||||||
if (!PyType_Check(b) ) {
|
assert(PyType_Check(b));
|
||||||
clear = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cls = (PyTypeObject *)b;
|
cls = (PyTypeObject *)b;
|
||||||
|
|
||||||
if (!PyType_HasFeature(cls, Py_TPFLAGS_HAVE_VERSION_TAG) ||
|
if (!PyType_HasFeature(cls, Py_TPFLAGS_HAVE_VERSION_TAG) ||
|
||||||
|
@ -488,7 +482,7 @@ type_set_bases(PyTypeObject *type, PyObject *value, void *context)
|
||||||
if (!PyType_Check(ob)) {
|
if (!PyType_Check(ob)) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
PyExc_TypeError,
|
PyExc_TypeError,
|
||||||
"%s.__bases__ must be tuple of old- or new-style classes, not '%s'",
|
"%s.__bases__ must be tuple of classes, not '%s'",
|
||||||
type->tp_name, Py_TYPE(ob)->tp_name);
|
type->tp_name, Py_TYPE(ob)->tp_name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1619,7 +1613,7 @@ mro_internal(PyTypeObject *type)
|
||||||
type->tp_mro = tuple;
|
type->tp_mro = tuple;
|
||||||
|
|
||||||
type_mro_modified(type, type->tp_mro);
|
type_mro_modified(type, type->tp_mro);
|
||||||
/* corner case: the old-style super class might have been hidden
|
/* corner case: the super class might have been hidden
|
||||||
from the custom MRO */
|
from the custom MRO */
|
||||||
type_mro_modified(type, type->tp_bases);
|
type_mro_modified(type, type->tp_bases);
|
||||||
|
|
||||||
|
@ -1676,9 +1670,8 @@ best_base(PyObject *bases)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (base == NULL)
|
assert (base != NULL);
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"a new-style class can't have only classic bases");
|
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3196,7 +3189,7 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
|
||||||
}
|
}
|
||||||
if (!PyType_Check(value)) {
|
if (!PyType_Check(value)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"__class__ must be set to new-style class, not '%s' object",
|
"__class__ must be set to a class, not '%s' object",
|
||||||
Py_TYPE(value)->tp_name);
|
Py_TYPE(value)->tp_name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -3811,8 +3804,8 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
|
||||||
that the extension type's own factory function ensures).
|
that the extension type's own factory function ensures).
|
||||||
Heap types, of course, are under our control, so they do
|
Heap types, of course, are under our control, so they do
|
||||||
inherit tp_new; static extension types that specify some
|
inherit tp_new; static extension types that specify some
|
||||||
other built-in type as the default are considered
|
other built-in type as the default also
|
||||||
new-style-aware so they also inherit object.__new__. */
|
inherit object.__new__. */
|
||||||
if (base != &PyBaseObject_Type ||
|
if (base != &PyBaseObject_Type ||
|
||||||
(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
|
(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
|
||||||
if (type->tp_new == NULL)
|
if (type->tp_new == NULL)
|
||||||
|
@ -6352,7 +6345,7 @@ supercheck(PyTypeObject *type, PyObject *obj)
|
||||||
{
|
{
|
||||||
/* Check that a super() call makes sense. Return a type object.
|
/* Check that a super() call makes sense. Return a type object.
|
||||||
|
|
||||||
obj can be a new-style class, or an instance of one:
|
obj can be a class, or an instance of one:
|
||||||
|
|
||||||
- If it is a class, it must be a subclass of 'type'. This case is
|
- If it is a class, it must be a subclass of 'type'. This case is
|
||||||
used for class methods; the return value is obj.
|
used for class methods; the return value is obj.
|
||||||
|
|
|
@ -665,7 +665,7 @@ PyErr_NewException(const char *name, PyObject *base, PyObject *dict)
|
||||||
if (bases == NULL)
|
if (bases == NULL)
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
/* Create a real new-style class. */
|
/* Create a real class. */
|
||||||
result = PyObject_CallFunction((PyObject *)&PyType_Type, "sOO",
|
result = PyObject_CallFunction((PyObject *)&PyType_Type, "sOO",
|
||||||
dot+1, bases, dict);
|
dot+1, bases, dict);
|
||||||
failure:
|
failure:
|
||||||
|
|
|
@ -474,7 +474,7 @@ Py_Finalize(void)
|
||||||
flush_std_files();
|
flush_std_files();
|
||||||
|
|
||||||
/* Collect final garbage. This disposes of cycles created by
|
/* Collect final garbage. This disposes of cycles created by
|
||||||
* new-style class definitions, for example.
|
* class definitions, for example.
|
||||||
* XXX This is disabled because it caused too many problems. If
|
* XXX This is disabled because it caused too many problems. If
|
||||||
* XXX a __del__ or weakref callback triggers here, Python code has
|
* XXX a __del__ or weakref callback triggers here, Python code has
|
||||||
* XXX a hard time running, because even the sys module has been
|
* XXX a hard time running, because even the sys module has been
|
||||||
|
@ -1348,11 +1348,6 @@ parse_syntax_error(PyObject *err, PyObject **message, const char **filename,
|
||||||
_Py_IDENTIFIER(offset);
|
_Py_IDENTIFIER(offset);
|
||||||
_Py_IDENTIFIER(text);
|
_Py_IDENTIFIER(text);
|
||||||
|
|
||||||
/* old style errors */
|
|
||||||
if (PyTuple_Check(err))
|
|
||||||
return PyArg_ParseTuple(err, "O(ziiz)", message, filename,
|
|
||||||
lineno, offset, text);
|
|
||||||
|
|
||||||
/* new style errors. `err' is an instance */
|
/* new style errors. `err' is an instance */
|
||||||
|
|
||||||
if (! (v = _PyObject_GetAttrId(err, &PyId_msg)))
|
if (! (v = _PyObject_GetAttrId(err, &PyId_msg)))
|
||||||
|
|
|
@ -402,7 +402,7 @@ class ProxyAlreadyVisited(object):
|
||||||
|
|
||||||
|
|
||||||
def _write_instance_repr(out, visited, name, pyop_attrdict, address):
|
def _write_instance_repr(out, visited, name, pyop_attrdict, address):
|
||||||
'''Shared code for use by old-style and new-style classes:
|
'''Shared code for use by all classes:
|
||||||
write a representation to file-like object "out"'''
|
write a representation to file-like object "out"'''
|
||||||
out.write('<')
|
out.write('<')
|
||||||
out.write(name)
|
out.write(name)
|
||||||
|
@ -481,7 +481,7 @@ class HeapTypeObjectPtr(PyObjectPtr):
|
||||||
|
|
||||||
def proxyval(self, visited):
|
def proxyval(self, visited):
|
||||||
'''
|
'''
|
||||||
Support for new-style classes.
|
Support for classes.
|
||||||
|
|
||||||
Currently we just locate the dictionary using a transliteration to
|
Currently we just locate the dictionary using a transliteration to
|
||||||
python of _PyObject_GetDictPtr, ignoring descriptors
|
python of _PyObject_GetDictPtr, ignoring descriptors
|
||||||
|
@ -498,7 +498,7 @@ class HeapTypeObjectPtr(PyObjectPtr):
|
||||||
attr_dict = {}
|
attr_dict = {}
|
||||||
tp_name = self.safe_tp_name()
|
tp_name = self.safe_tp_name()
|
||||||
|
|
||||||
# New-style class:
|
# Class:
|
||||||
return InstanceProxy(tp_name, attr_dict, long(self._gdbval))
|
return InstanceProxy(tp_name, attr_dict, long(self._gdbval))
|
||||||
|
|
||||||
def write_repr(self, out, visited):
|
def write_repr(self, out, visited):
|
||||||
|
@ -670,44 +670,6 @@ class PyDictObjectPtr(PyObjectPtr):
|
||||||
pyop_value.write_repr(out, visited)
|
pyop_value.write_repr(out, visited)
|
||||||
out.write('}')
|
out.write('}')
|
||||||
|
|
||||||
class PyInstanceObjectPtr(PyObjectPtr):
|
|
||||||
_typename = 'PyInstanceObject'
|
|
||||||
|
|
||||||
def proxyval(self, visited):
|
|
||||||
# Guard against infinite loops:
|
|
||||||
if self.as_address() in visited:
|
|
||||||
return ProxyAlreadyVisited('<...>')
|
|
||||||
visited.add(self.as_address())
|
|
||||||
|
|
||||||
# Get name of class:
|
|
||||||
in_class = self.pyop_field('in_class')
|
|
||||||
cl_name = in_class.pyop_field('cl_name').proxyval(visited)
|
|
||||||
|
|
||||||
# Get dictionary of instance attributes:
|
|
||||||
in_dict = self.pyop_field('in_dict').proxyval(visited)
|
|
||||||
|
|
||||||
# Old-style class:
|
|
||||||
return InstanceProxy(cl_name, in_dict, long(self._gdbval))
|
|
||||||
|
|
||||||
def write_repr(self, out, visited):
|
|
||||||
# Guard against infinite loops:
|
|
||||||
if self.as_address() in visited:
|
|
||||||
out.write('<...>')
|
|
||||||
return
|
|
||||||
visited.add(self.as_address())
|
|
||||||
|
|
||||||
# Old-style class:
|
|
||||||
|
|
||||||
# Get name of class:
|
|
||||||
in_class = self.pyop_field('in_class')
|
|
||||||
cl_name = in_class.pyop_field('cl_name').proxyval(visited)
|
|
||||||
|
|
||||||
# Get dictionary of instance attributes:
|
|
||||||
pyop_in_dict = self.pyop_field('in_dict')
|
|
||||||
|
|
||||||
_write_instance_repr(out, visited,
|
|
||||||
cl_name, pyop_in_dict, self.as_address())
|
|
||||||
|
|
||||||
class PyListObjectPtr(PyObjectPtr):
|
class PyListObjectPtr(PyObjectPtr):
|
||||||
_typename = 'PyListObject'
|
_typename = 'PyListObject'
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue