[Python-Dev] augmented assignment

Thomas Wouters thomas@xs4all.net
Mon, 7 Aug 2000 15:07:11 +0200


--0OAP2g/MAC+5xKAE
Content-Type: text/plain; charset=us-ascii
I 'finished' the new augmented assignment patch yesterday, following the
suggestions made by Guido about using INPLACE_* bytecodes rather than
special GETSET_* opcodes.
I ended up with 13 new opcodes: INPLACE_* opcodes for the 11 binary
operation opcodes, DUP_TOPX which duplicates a number of stack items instead
of just the topmost item, and ROT_FOUR.
I thought I didn't need ROT_FOUR if we had DUP_TOPX but I hadn't realized
assignment needs the new value at the bottom of the 'stack', and the objects
that are used in the assignment above that. So ROT_FOUR is necessary in the
case of slice-assignment:
a[b:c] += i
LOAD a			[a]
LOAD b			[a, b]
LOAD c			[a, b, c]
DUP_TOPX 3		[a, b, c, a, b, c]
SLICE+3			[a, b, c, a[b:c]]
LOAD i			[a, b, c, a[b:c], i]
INPLACE_ADD		[a, b, c, result]
ROT_FOUR		[result, a, b, c]
STORE_SLICE+3		[]
When (and if) the *SLICE opcodes are removed, ROT_FOUR can, too :)
The patch is 'done' in my opinion, except for two tiny things:
- PyNumber_InPlacePower() takes just two arguments, not three. Three
argument power() does such 'orrible things to coerce all the arguments, and
you can't do augmented-assignment-three-argument-power anyway. If it's added
it would be for the API only, and I'm not sure if it's worth it :P
- I still don't like the '_ab_' names :) I think __inplace_add__ or __iadd__
 is better, but that's just me.
The PEP is also 'done'. Feedback is more than welcome, including spelling
fixes and the like. I've attached the PEP to this mail, for convenience.
-- 
Thomas Wouters <thomas@xs4all.net>
Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
--0OAP2g/MAC+5xKAE
Content-Type: text/plain
Content-Disposition: attachment; filename="pep-0203.txt"
PEP: 203
Title: Augmented Assignments
Version: $Revision: 1.4 $
Owner: thomas@xs4all.net (Thomas Wouters)
Python-Version: 2.0
Status: Draft
Introduction
 This PEP describes the `augmented assignment' proposal for Python
 2.0. This PEP tracks the status and ownership of this feature,
 slated for introduction in Python 2.0. It contains a description
 of the feature and outlines changes necessary to support the
 feature. This PEP summarizes discussions held in mailing list
 forums, and provides URLs for further information, where
 appropriate. The CVS revision history of this file contains the
 definitive historical record.
Proposed semantics
 The proposed patch that adds augmented assignment to Python
 introduces the following new operators:
 
 += -= *= /= %= **= <<= >>= &= ^= |=
 
 They implement the same operator as their normal binary form, with
 the exception that the operation is done `in-place' whenever
 possible.
 
 They truly behave as augmented assignment, in that they perform
 all of the normal load and store operations, in addition to the
 binary operation they are intended to do. So, given the expression:
 
 x += y
 
 The object `x' is loaded, then added with 1, and the resulting
 object is stored back in the original place. The precise action
 performed on the two arguments depends on the type of `x', and
 possibly of `y'.
 The idea behind augmented assignment in Python is that it isn't
 just an easier way to write the common practice of storing the
 result of a binary operation in its left-hand operand, but also a
 way for the left-hand operand in question to know that it should
 operate 'on itself', rather than creating a modified copy of
 itself.
 To make this possible, a number of new `hooks' are added to Python
 classes and C extention types, which are called when the object in
 question is used as the left hand side of an augmented assignment
 operation. If the class or type does not implement the `in-place'
 hooks, the normal hooks for the particular binary operation are
 used.
 
 So, given an instance object `x', the expression
 
 x += y
 
 tries to call x.__add_ab__(y), which is the 'in-place' variant of
 __add__. If __add_ab__ 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 __add_ab__, because that
 would require for `y' to know how to in-place modify `x', which is
 an unsafe assumption. The __add_ab__ hook should behave exactly
 like __add__, returning the result of the operation (which could
 be `self') which is to be stored in the variable `x'.
 
 For C extention 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.
New methods
 The proposed implementation adds the following 11 possible `hooks'
 which Python classes can implement to overload the augmented
 assignment operations:
 
 __add_ab__
 __sub_ab__
 __mul_ab__
 __div_ab__
 __mod_ab__
 __pow_ab__
 __lshift_ab__
 __rshift_ab__
 __and_ab__
 __xor_ab__
 __or_ab__
 
 The `__add_ab__' name is one proposed by Guido[1], and stands for `and
 becomes'. Other proposed names include '__iadd__', `__add_in__'
 `__inplace_add__'
 For C extention types, the following struct members are added:
 
 To PyNumberMethods:
 binaryfunc nb_inplace_add;
 binaryfunc nb_inplace_subtract;
 binaryfunc nb_inplace_multiply;
 binaryfunc nb_inplace_divide;
 binaryfunc nb_inplace_remainder;
 binaryfunc nb_inplace_power;
 binaryfunc nb_inplace_lshift;
 binaryfunc nb_inplace_rshift;
 binaryfunc nb_inplace_and;
 binaryfunc nb_inplace_xor;
 binaryfunc nb_inplace_or;
 To PySequenceMethods:
 binaryfunc sq_inplace_concat;
 intargfunc sq_inplace_repeat;
 In order to keep binary compatibility, the tp_flags TypeObject
 member is used to determine whether the TypeObject in question has
 allocated room for these slots. Until a clean break in binary
 compatibility is made (which may or may not happen before 2.0)
 code that wants to use one of the new struct members must first
 check that they are available with the 'PyType_HasFeature()' macro:
 
 if (PyType_HasFeature(x->ob_type, Py_TPFLAGS_HAVE_INPLACE_OPS) &&
 x->ob_type->tp_as_number && x->ob_type->tp_as_number->nb_inplace_add) {
 /* ... */
 This check must be made even before testing the method slots for
 NULL values! The macro only tests whether the slots are available,
 not whether they are filled with methods or not.
Implementation
 The current implementation of augmented assignment[2] adds, in
 addition to the methods and slots alread covered, 13 new bytecodes
 and 13 new API functions.
 
 The API functions are simply in-place versions of the current
 binary-operation API functions:
 
 PyNumber_InPlaceAdd(PyObject *o1, PyObject *o2);
 PyNumber_InPlaceSubtract(PyObject *o1, PyObject *o2);
 PyNumber_InPlaceMultiply(PyObject *o1, PyObject *o2);
 PyNumber_InPlaceDivide(PyObject *o1, PyObject *o2);
 PyNumber_InPlaceRemainder(PyObject *o1, PyObject *o2);
 PyNumber_InPlacePower(PyObject *o1, PyObject *o2);
 PyNumber_InPlaceLshift(PyObject *o1, PyObject *o2);
 PyNumber_InPlaceRshift(PyObject *o1, PyObject *o2);
 PyNumber_InPlaceAnd(PyObject *o1, PyObject *o2);
 PyNumber_InPlaceXor(PyObject *o1, PyObject *o2);
 PyNumber_InPlaceOr(PyObject *o1, PyObject *o2);
 PySequence_InPlaceConcat(PyObject *o1, PyObject *o2);
 PySequence_InPlaceRepeat(PyObject *o, int count);
 They call either the Python class hooks (if either of the objects
 is a Python class instance) or the C type's number or sequence
 methods.
 The new bytecodes are:
 INPLACE_ADD
 INPLACE_SUBTRACT
 INPLACE_MULTIPLY
 INPLACE_DIVIDE
 INPLACE_REMAINDER
 INPLACE_POWER
 INPLACE_LEFTSHIFT
 INPLACE_RIGHTSHIFT
 INPLACE_AND
 INPLACE_XOR
 INPLACE_OR
 ROT_FOUR
 DUP_TOPX
 
 The INPLACE_* bytecodes mirror the BINARY_* bytecodes, except that
 they are implemented as calls to the 'InPlace' API functions. The
 other two bytecodes are 'utility' bytecodes: ROT_FOUR behaves like
 ROT_THREE except that the four topmost stack items are rotated.
 
 DUP_TOPX is a bytecode that takes a single argument, which should
 be an integer between 1 and 5 (inclusive) which is the number of
 items to duplicate in one block. Given a stack like this (where
 the left side of the list is the 'top' of the stack):
 [a, b, c, d, e, f, g]
 
 "DUP_TOPX 3" would duplicate the top 3 items, resulting in this
 stack:
 
 [a, b, c, d, e, f, g, e, f, g]
 DUP_TOPX with an argument of 1 is the same as DUP_TOP. The limit
 of 5 is purely an implementation limit. The implementation of
 augmented assignment requires only DUP_TOPX with an argument of 2
 and 3, and could do without this new opcode at the cost of a fair
 number of DUP_TOP and ROT_*.
Copyright
 This document has been placed in the public domain.
References
 [1] http://www.python.org/pipermail/python-list/2000-June/059556.html
 [2]
http://sourceforge.net/patch?func=detailpatch&patch_id=100699&group_id=5470

Local Variables:
mode: indented-text
indent-tabs-mode: nil
End:
--0OAP2g/MAC+5xKAE--

AltStyle によって変換されたページ (->オリジナル) /