Added a section on multiple inheritance.
This commit is contained in:
parent
9006318a33
commit
3294596182
107
pep-0253.txt
107
pep-0253.txt
|
@ -282,7 +282,7 @@ Making a type a factory for its instances
|
|||
should also register the object with the garbage collection
|
||||
subsystem if the type supports garbage collection. This slot
|
||||
exists so that derived types can override the memory allocation
|
||||
policy (e.g. which heap is being used) separately from the
|
||||
policy (like which heap is being used) separately from the
|
||||
initialization code. The signature is:
|
||||
|
||||
PyObject *tp_alloc(PyTypeObject *type, int nitems)
|
||||
|
@ -368,9 +368,10 @@ Preparing a type for subtyping
|
|||
The tp_free() slot should be used to free the memory and
|
||||
unregister the object with the garbage collection subsystem, and
|
||||
can be overridden by a derived class; tp_dealloc() should
|
||||
deinitialize the object (e.g. by calling Py_XDECREF() for various
|
||||
sub-objects) and then call tp_free() to deallocate the memory.
|
||||
The signature for tp_dealloc() is the same as it always was:
|
||||
deinitialize the object (usually by calling Py_XDECREF() for
|
||||
various sub-objects) and then call tp_free() to deallocate the
|
||||
memory. The signature for tp_dealloc() is the same as it always
|
||||
was:
|
||||
|
||||
void tp_dealloc(PyObject *object)
|
||||
|
||||
|
@ -636,6 +637,94 @@ Subtyping in Python
|
|||
dictionary (the third argument to the call to M).
|
||||
|
||||
|
||||
Multiple Inheritance
|
||||
|
||||
The Python class statement supports multiple inheritance, and we
|
||||
will also support multiple inheritance involving built-in types.
|
||||
|
||||
However, there are some restrictions. The C runtime architecture
|
||||
doesn't make it feasible to have a meaningful subtype of two
|
||||
different built-in types except in a few degenerate cases.
|
||||
Changing the C runtime to support fully general multiple
|
||||
inheritance would be too much of an upheaval of the code base.
|
||||
|
||||
The main problem with multiple inheritance from different built-in
|
||||
types stems from the fact that the C implementation of built-in
|
||||
types accesses structure members directly; the C compiler
|
||||
generates an offset relative to the object pointer and that's
|
||||
that. For example, the list and dictionary type structures each
|
||||
declare a number of different but overlapping structure members.
|
||||
A C function accessing an object expecting a list won't work when
|
||||
passed a dictionary, and vice versa, and there's not much we could
|
||||
do about this without rewriting all code that accesses lists and
|
||||
dictionaries. This would be too much work, so we won't do this.
|
||||
|
||||
The problem with multiple inheritance is caused by conflicting
|
||||
structure member allocations. Classes defined in Python normally
|
||||
don't store their instance variables in structure members: they
|
||||
are stored in an instance dictionary. This is the key to a
|
||||
partial solution. Suppose we have the following two classes:
|
||||
|
||||
class A(dictionary):
|
||||
def foo(self): pass
|
||||
|
||||
class B(dictionary):
|
||||
def bar(self): pass
|
||||
|
||||
class C(A, B): pass
|
||||
|
||||
(Here, 'dictionary' is the type of built-in dictionary objects,
|
||||
a.k.a. type({}) or {}.__class__ or types.DictType.) If we look at
|
||||
the structure lay-out, we find that an A instance has the lay-out
|
||||
of a dictionary followed by the __dict__ pointer, and a B instance
|
||||
has the same lay-out; since there are no structure member lay-out
|
||||
conflicts, this is okay.
|
||||
|
||||
Here's another example:
|
||||
|
||||
class X(object):
|
||||
def foo(self): pass
|
||||
|
||||
class Y(dictionary):
|
||||
def bar(self): pass
|
||||
|
||||
class Z(X, Y): pass
|
||||
|
||||
(Here, 'object' is the base for all built-in types; its structure
|
||||
lay-out only contains the ob_refcnt and ob_type members.) This
|
||||
example is more complicated, because the __dict__ pointer for X
|
||||
instances has a different offset than that for Y instances. Where
|
||||
is the __dict__ pointer for Z instances? The answer is that the
|
||||
offset for the __dict__ pointer is not hardcoded, it is stored in
|
||||
the type object.
|
||||
|
||||
Suppose on a particular machine an 'object' structure is 8 bytes
|
||||
long, and a 'dictionary' struct is 60 bytes, and an object pointer
|
||||
is 4 bytes. Then an X structure is 12 bytes (an object structure
|
||||
followed by a __dict__ pointer), and a Y structure is 64 bytes (a
|
||||
dictionary structure followed by a __dict__ pointer). The Z
|
||||
structure has the same lay-out as the Y structure in this example.
|
||||
Each type object (X, Y and Z) has a "__dict__ offset" which is
|
||||
used to find the __dict__ pointer. Thus, the recipe for looking
|
||||
up an instance variable is:
|
||||
|
||||
1. get the type of the instance
|
||||
2. get the __dict__ offset from the type object
|
||||
3. add the __dict__ offset to the instance pointer
|
||||
4. look in the resulting address to find a dictionary reference
|
||||
5. look up the instance variable name in that dictionary
|
||||
|
||||
Of course, this recipe can only be implemented in C, and I have
|
||||
left out some details. But this allows us to use multiple
|
||||
inheritance patterns similar to the ones we can use with classic
|
||||
classes.
|
||||
|
||||
XXX I should write up the complete algorithm here to determine
|
||||
base class compatibility, but I can't be bothered right now. Look
|
||||
at best_base() in typeobject.c in the implementation mentioned
|
||||
below.
|
||||
|
||||
|
||||
XXX To be done
|
||||
|
||||
Additional topics to be discussed in this PEP:
|
||||
|
@ -643,18 +732,24 @@ XXX To be done
|
|||
- class methods and static methods
|
||||
|
||||
- mapping between type object slots (tp_foo) and special methods
|
||||
(__foo__)
|
||||
(__foo__) (actually, this may belong in PEP 252)
|
||||
|
||||
- built-in names for built-in types (object, int, str, list etc.)
|
||||
|
||||
- multiple inheritance restrictions
|
||||
- method resolution order
|
||||
|
||||
- __dict__
|
||||
|
||||
- __slots__
|
||||
|
||||
- the HEAPTYPE and DYNAMICTYPE flag bits
|
||||
|
||||
- GC support
|
||||
|
||||
- API docs for all the new functions
|
||||
|
||||
- high level user overview
|
||||
|
||||
|
||||
Implementation
|
||||
|
||||
|
|
Loading…
Reference in New Issue