Update PEP to reflect reality. Explain the current mechanism the InPlace functions use to find the right function to call, and when to coerce or not.

This commit is contained in:
Thomas Wouters 2000-08-25 11:11:25 +00:00
parent a448946a31
commit f32f15658a
1 changed files with 69 additions and 28 deletions

View File

@ -63,25 +63,76 @@ Proposed semantics
x += y
tries to call x.__iadd__(y), which is the `in-place' variant of
__add__. If __iadd__ is not present, x.__add__(y) is
attempted, and finally y.__radd__(x) if __add__ is missing too.
There is no `right-hand-side' variant of __iadd__, because that
would require for `y' to know how to in-place modify `x', which is
unsafe to say the least. The __iadd__ hook should behave similar
to __add__, returning the result of the operation (which could be
`self') which is to be stored in the variable `x'.
__add__. If __iadd__ is not present, x.__add__(y) is attempted,
and finally y.__radd__(x) if __add__ is missing too. There is no
`right-hand-side' variant of __iadd__, because that would require
for `y' to know how to in-place modify `x', which is unsafe to say
the least. The __iadd__ hook should behave similar to __add__,
returning the result of the operation (which could be `self')
which is to be assigned to the variable `x'.
For C extension types, the `hooks' are members of the
PyNumberMethods and PySequenceMethods structures, and are called
in exactly the same manner as the existing non-inplace operations,
including argument coercion. C methods should also take care to
return a new reference to the result object, whether it's the same
object or a new one. So if the original object is returned, it
should be INCREF()'d appropriately.
PyNumberMethods and PySequenceMethods structures. Some special
semantics apply to make the use of these methods, and the mixing
of Python instance objects and C types, as unsurprising as
possible.
In the generic case of `x <augop> y' (or a similar case using the
PyNumber_InPlace API functions) the principal object being
operated on is `x'. This differs from normal binary operations,
where `x' and `y' could be considered `co-operating', because
unlike in binary operations, the operands in an in-place operation
cannot be swapped. However, in-place operations do fall back to
normal binary operations when in-place modification is not
supported, resuling in the following rules:
- If the left-hand object (`x') is an instance object, and it
has a `__coerce__' method, call that function with `y' as the
argument. If coercion succeeds, and the resulting left-hand
object is a different object than `x', stop processing it as
in-place and call the appropriate function for the normal binary
operation, with the coerced `x' and `y' as arguments. The result
of the operation is whatever that function returns.
If coercion does not yield a different object for `x', or `x'
does not define a `__coerce__' method, and `x' has the
appropriate `__ihook__' for this operation, call that method
with `y' as the argument, and the result of the operation is
whatever that method returns.
- Otherwise, if the left-hand object is not an instance object,
but its type does define the in-place function for this
operation, call that function with `x' and `y' as the arguments,
and the result of the operation is whatever that function
returns.
Note that no coercion on either `x' or `y' is done in this case,
and it's perfectly valid for a C type to receive an instance
object as the second argument; that is something that cannot
happen with normal binary operations.
- Otherwise, process it exactly as a normal binary operation (not
in-place), including argument coercion. In short, if either
argument is an instance object, resolve the operation through
`__coerce__', `__hook__' and `__rhook__'. Otherwise, both
objects are C types, and they are coerced and passed to the
appropriate function.
- If no way to process the operation can be found, raise a
TypeError with an error message specific to the operation.
- Some special casing exists to account for the case of `+' and
`*', which have a special meaning for sequences: for `+',
sequence concatenation, no coercion what so ever is done if a C
type defines sq_concat or sq_inplace_concat. For `*', sequence
repeating, `y' is converted to a C integer before calling either
sq_inplace_repeat and sq_repeat. This is done even if `y' is an
instance, though not if `x' is an instance.
The in-place function should always return a new reference, either
to the old `x' object if the operation was indeed performed
in-place, or to a new object.
[XXX so I am accepting this, but I'm a bit worried about the
argument coercion. For x+=y, if x supports augmented assignment,
y should only be cast to x's type, not the other way around!]
Rationale
@ -133,7 +184,7 @@ Rationale
Augmented assignment won't solve all the problems for these
packages, since some operations cannot be expressed in the limited
set of binary operators to start with, but it is a start. A
different PEP[3] is looking at adding new operators.
different PEP[2] is looking at adding new operators.
New methods
@ -194,7 +245,7 @@ New methods
Implementation
The current implementation of augmented assignment[2] adds, in
The current implementation of augmented assignment[1] adds, in
addition to the methods and slots already covered, 13 new bytecodes
and 13 new API functions.
@ -272,16 +323,6 @@ Open Issues
bytecode at this time.
It is not possible to do an inplace operation in the variant of
<builtin type> += <instance object>
Instead, the instance objects' __radd__ hook is called, with the
builtin type as argument. The same goes for the other operations.
It might necessary to add a right-hand version of __add_ab__ after
all, to support something like that.
Copyright
This document has been placed in the public domain.