Small rewordings based on Terry Reedy's feedback (finally).

Added a few more open issues.
This commit is contained in:
Guido van Rossum 2001-09-08 11:31:52 +00:00
parent 17807b8b31
commit aaebded223
1 changed files with 63 additions and 38 deletions

View File

@ -25,11 +25,11 @@ Introduction
various flags, but most slots are pointers to functions to
implement various kinds of behaviors. A NULL pointer means that
the type does not implement the specific behavior; in that case
the system may provide a default behavior in that case or raise an
exception when the behavior is invoked. Some collections of
function pointers that are usually defined together are obtained
indirectly via a pointer to an additional structure containing
more function pointers.
the system may provide a default behavior or raise an exception
when the behavior is invoked for an instance of the type. Some
collections of function pointers that are usually defined together
are obtained indirectly via a pointer to an additional structure
containing more function pointers.
While the details of initializing a PyTypeObject structure haven't
been documented as such, they are easily gleaned from the examples
@ -171,41 +171,38 @@ Making a type a factory for its instances
memory. As of Python 2.0, they also have to interface with the
garbage collection subsystem, if the type chooses to participate
in garbage collection (which is optional, but strongly recommended
for so-called "container" types: types that may contain arbitrary
references to other objects, and hence may participate in
reference cycles).
for so-called "container" types: types that may contain references
to other objects, and hence may participate in reference cycles).
In this proposal, type objects can be factory functions for their
instances, making the types directly callable from Python. This
mimics the way classes are instantiated. Of course, the C APIs
for creating instances of various built-in types will remain valid
and probably the most common; and not all types will become their
own factory functions.
mimics the way classes are instantiated. The C APIs for creating
instances of various built-in types will remain valid and in some
cases more efficient. Not all types will become their own factory
functions.
The type object has a new slot, tp_new, which can act as a factory
for instances of the type. Types are made callable by providing a
tp_call slot in PyType_Type (the metatype); the slot
implementation function looks for the tp_new slot of the type that
is being called.
for instances of the type. Types are now callable, because the
tp_call slot is set in PyType_Type (the metatype); the function
looks for the tp_new slot of the type that is being called.
(Confusion alert: the tp_call slot of a regular type object (such
as PyInt_Type or PyList_Type) defines what happens when
*instances* of that type are called; in particular, the tp_call
slot in the function type, PyFunction_Type, is the key to making
functions callable. As another example, PyInt_Type.tp_call is
NULL, because integers are not callable. The new paradigm makes
*type objects* callable. Since type objects are instances of
their metatype (PyType_Type), the metatype's tp_call slot
(PyType_Type.tp_call) points to a function that is invoked when
any type object is called. Now, since each type has do do
something different to create an instance of itself,
PyType_Type.tp_call immediately defers to the tp_new slot of the
type that is being called. To add to the confusion, PyType_Type
itself is also callable: its tp_new slot creates a new type. This
is used by the class statement (via the Don Beaudry hook, see
above). And what makes PyType_Type callable? The tp_call slot of
*its* metatype -- but since it is its own metatype, that is its
own tp_call slot!)
Explanation: the tp_call slot of a regular type object (such as
PyInt_Type or PyList_Type) defines what happens when *instances*
of that type are called; in particular, the tp_call slot in the
function type, PyFunction_Type, is the key to making functions
callable. As another example, PyInt_Type.tp_call is NULL, because
integers are not callable. The new paradigm makes *type objects*
callable. Since type objects are instances of their metatype
(PyType_Type), the metatype's tp_call slot (PyType_Type.tp_call)
points to a function that is invoked when any type object is
called. Now, since each type has do do something different to
create an instance of itself, PyType_Type.tp_call immediately
defers to the tp_new slot of the type that is being called.
PyType_Type itself is also callable: its tp_new slot creates a new
type. This is used by the class statement (formalizing the Don
Beaudry hook, see above). And what makes PyType_Type callable?
The tp_call slot of *its* metatype -- but since it is its own
metatype, that is its own tp_call slot!
If the type's tp_new slot is NULL, an exception is raised.
Otherwise, the tp_new slot is called. The signature for the
@ -775,8 +772,8 @@ Method resolution order (the lookup rule)
saved), defeating the whole purpose of inheriting from C in the
first place.
Why was this not a problem in classic Python? Diamond diagrams is
found rarely in classic Python class hierarchies. Most class
Why was this not a problem in classic Python? Diamond diagrams
are rarely found in classic Python class hierarchies. Most class
hierarchies use single inheritance, and multiple inheritance is
usually confined to mix-in classes. In fact, the problem shown
here is probably the reason why multiple inheritance is impopular
@ -892,22 +889,50 @@ XXX To be done
- built-in names for built-in types (object, int, str, list etc.)
- __dict__
- __dict__ and dictoffset
- __slots__
- __dynamic__
- the HEAPTYPE and DYNAMICTYPE flag bits
- GC support
- API docs for all the new functions
- using __new__
- how to use __new__
- writing metaclasses (using mro() etc.)
- high level user overview
- open issues:
- performance
- pickling, __reduce__
- do we need __coerce__, __del__?
- should we return to the old __getattr__ semantics, and
introduce a new name (__getallattr__?) for the new semantics?
or introduce a new name (__getattrhook__?)for the old
semantics?
- whether __dynamic__ should be default
- assignment to __class__, __dict__, __bases__
- inconsistent naming
(e.g. tp_dealloc/tp_new/tp_init/tp_alloc/tp_free)
- add builtin alias 'dict' for 'dictionary'?
- when subclasses of dict/list etc. are passed to system
functions, the __getitem__ overrides (etc.) aren't always
used
Implementation