adding in-place operators to the operator module.

This commit is contained in:
Armin Rigo 2005-12-29 16:50:42 +00:00
parent ecc275bcef
commit f5bd3b442d
3 changed files with 190 additions and 1 deletions

View file

@ -237,6 +237,108 @@ sequence \var{v}.
\end{funcdesc}
Many operations have an ``in-place'' version. The following functions
provide a more primitive access to in-place operators than the usual
syntax does; for example, the statement \code{x += y} is equivalent to
\code{x = operator.iadd(x, y)}. Another way to put it is to say that
\code{z = operator.iadd(x, y)} is equivalent to the compound statement
\code{z = x; z += y}.
\begin{funcdesc}{iadd}{a, b}
\funcline{__iadd__}{a, b}
\code{a = iadd(a, b)} is equivalent to \code{a += b}.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{iand}{a, b}
\funcline{__iand__}{a, b}
\code{a = iand(a, b)} is equivalent to \code{a \&= b}.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{iconcat}{a, b}
\funcline{__iconcat__}{a, b}
\code{a = iconcat(a, b)} is equivalent to \code{a += b} for \var{a}
and \var{b} sequences.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{idiv}{a, b}
\funcline{__idiv__}{a, b}
\code{a = idiv(a, b)} is equivalent to \code{a /= b} when
\code{__future__.division} is not in effect.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{ifloordiv}{a, b}
\funcline{__ifloordiv__}{a, b}
\code{a = ifloordiv(a, b)} is equivalent to \code{a //= b}.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{ilshift}{a, b}
\funcline{__ilshift__}{a, b}
\code{a = ilshift(a, b)} is equivalent to \code{a <}\code{<= b}.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{imod}{a, b}
\funcline{__imod__}{a, b}
\code{a = imod(a, b)} is equivalent to \code{a \%= b}.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{imul}{a, b}
\funcline{__imul__}{a, b}
\code{a = imul(a, b)} is equivalent to \code{a *= b}.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{ior}{a, b}
\funcline{__ior__}{a, b}
\code{a = ior(a, b)} is equivalent to \code{a |= b}.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{ipow}{a, b}
\funcline{__ipow__}{a, b}
\code{a = ipow(a, b)} is equivalent to \code{a **= b}.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{irepeat}{a, b}
\funcline{__irepeat__}{a, b}
\code{a = irepeat(a, b)} is equivalent to \code{a *= b} where
\var{a} is a sequence and \var{b} is an integer.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{irshift}{a, b}
\funcline{__irshift__}{a, b}
\code{a = irshift(a, b)} is equivalent to \code{a >}\code{>= b}.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{isub}{a, b}
\funcline{__isub__}{a, b}
\code{a = isub(a, b)} is equivalent to \code{a -= b}.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{itruediv}{a, b}
\funcline{__itruediv__}{a, b}
\code{a = itruediv(a, b)} is equivalent to \code{a /= b} when
\code{__future__.division} is in effect.
\versionadded{2.5}
\end{funcdesc}
\begin{funcdesc}{ixor}{a, b}
\funcline{__ixor__}{a, b}
\code{a = ixor(a, b)} is equivalent to \code{a \textasciicircum= b}.
\versionadded{2.5}
\end{funcdesc}
The \module{operator} module also defines a few predicates to test the
type of objects. \note{Be careful not to misinterpret the
results of these functions; only \function{isCallable()} has any

View file

@ -412,6 +412,53 @@ class OperatorTestCase(unittest.TestCase):
self.assertEqual(operator.itemgetter(2,10,5)(data), ('2', '10', '5'))
self.assertRaises(TypeError, operator.itemgetter(2, 'x', 5), data)
def test_inplace(self):
class C(object):
def __iadd__ (self, other): return "iadd"
def __iand__ (self, other): return "iand"
def __idiv__ (self, other): return "idiv"
def __ifloordiv__(self, other): return "ifloordiv"
def __ilshift__ (self, other): return "ilshift"
def __imod__ (self, other): return "imod"
def __imul__ (self, other): return "imul"
def __ior__ (self, other): return "ior"
def __ipow__ (self, other): return "ipow"
def __irshift__ (self, other): return "irshift"
def __isub__ (self, other): return "isub"
def __itruediv__ (self, other): return "itruediv"
def __ixor__ (self, other): return "ixor"
def __getitem__(self, other): return 5 # so that C is a sequence
c = C()
self.assertEqual(operator.iadd (c, 5), "iadd")
self.assertEqual(operator.iand (c, 5), "iand")
self.assertEqual(operator.idiv (c, 5), "idiv")
self.assertEqual(operator.ifloordiv(c, 5), "ifloordiv")
self.assertEqual(operator.ilshift (c, 5), "ilshift")
self.assertEqual(operator.imod (c, 5), "imod")
self.assertEqual(operator.imul (c, 5), "imul")
self.assertEqual(operator.ior (c, 5), "ior")
self.assertEqual(operator.ipow (c, 5), "ipow")
self.assertEqual(operator.irshift (c, 5), "irshift")
self.assertEqual(operator.isub (c, 5), "isub")
self.assertEqual(operator.itruediv (c, 5), "itruediv")
self.assertEqual(operator.ixor (c, 5), "ixor")
self.assertEqual(operator.iconcat (c, c), "iadd")
self.assertEqual(operator.irepeat (c, 5), "imul")
self.assertEqual(operator.__iadd__ (c, 5), "iadd")
self.assertEqual(operator.__iand__ (c, 5), "iand")
self.assertEqual(operator.__idiv__ (c, 5), "idiv")
self.assertEqual(operator.__ifloordiv__(c, 5), "ifloordiv")
self.assertEqual(operator.__ilshift__ (c, 5), "ilshift")
self.assertEqual(operator.__imod__ (c, 5), "imod")
self.assertEqual(operator.__imul__ (c, 5), "imul")
self.assertEqual(operator.__ior__ (c, 5), "ior")
self.assertEqual(operator.__ipow__ (c, 5), "ipow")
self.assertEqual(operator.__irshift__ (c, 5), "irshift")
self.assertEqual(operator.__isub__ (c, 5), "isub")
self.assertEqual(operator.__itruediv__ (c, 5), "itruediv")
self.assertEqual(operator.__ixor__ (c, 5), "ixor")
self.assertEqual(operator.__iconcat__ (c, c), "iadd")
self.assertEqual(operator.__irepeat__ (c, 5), "imul")
def test_main(verbose=None):
import sys

View file

@ -80,9 +80,23 @@ spami(op_not_ , PyObject_Not)
spam2(op_and_ , PyNumber_And)
spam2(op_xor , PyNumber_Xor)
spam2(op_or_ , PyNumber_Or)
spam2(op_iadd , PyNumber_InPlaceAdd)
spam2(op_isub , PyNumber_InPlaceSubtract)
spam2(op_imul , PyNumber_InPlaceMultiply)
spam2(op_idiv , PyNumber_InPlaceDivide)
spam2(op_ifloordiv , PyNumber_InPlaceFloorDivide)
spam2(op_itruediv , PyNumber_InPlaceTrueDivide)
spam2(op_imod , PyNumber_InPlaceRemainder)
spam2(op_ilshift , PyNumber_InPlaceLshift)
spam2(op_irshift , PyNumber_InPlaceRshift)
spam2(op_iand , PyNumber_InPlaceAnd)
spam2(op_ixor , PyNumber_InPlaceXor)
spam2(op_ior , PyNumber_InPlaceOr)
spami(isSequenceType , PySequence_Check)
spam2(op_concat , PySequence_Concat)
spamoi(op_repeat , PySequence_Repeat)
spam2(op_iconcat , PySequence_InPlaceConcat)
spamoi(op_irepeat , PySequence_InPlaceRepeat)
spami2b(op_contains , PySequence_Contains)
spami2b(sequenceIncludes, PySequence_Contains)
spami2(indexOf , PySequence_Index)
@ -107,6 +121,15 @@ op_pow(PyObject *s, PyObject *a)
return NULL;
}
static PyObject*
op_ipow(PyObject *s, PyObject *a)
{
PyObject *a1, *a2;
if (PyArg_UnpackTuple(a,"ipow", 2, 2, &a1, &a2))
return PyNumber_InPlacePower(a1, a2, Py_None);
return NULL;
}
static PyObject*
is_(PyObject *s, PyObject *a)
{
@ -224,10 +247,26 @@ spam2o(not_,__not__, "not_(a) -- Same as not a.")
spam2(and_,__and__, "and_(a, b) -- Same as a & b.")
spam2(xor,__xor__, "xor(a, b) -- Same as a ^ b.")
spam2(or_,__or__, "or_(a, b) -- Same as a | b.")
spam2(iadd,__iadd__, "iadd(a, b) -- Same as a += b.")
spam2(isub,__isub__, "isub(a, b) -- Same as a -= b.")
spam2(imul,__imul__, "imul(a, b) -- Same as a *= b.")
spam2(idiv,__idiv__, "idiv(a, b) -- Same as a /= b when __future__.division is not in effect.")
spam2(ifloordiv,__ifloordiv__, "ifloordiv(a, b) -- Same as a //= b.")
spam2(itruediv,__itruediv__, "itruediv(a, b) -- Same as a /= b when __future__.division is in effect.")
spam2(imod,__imod__, "imod(a, b) -- Same as a %= b.")
spam2(ilshift,__ilshift__, "ilshift(a, b) -- Same as a <<= b.")
spam2(irshift,__irshift__, "irshift(a, b) -- Same as a >>= b.")
spam2(iand,__iand__, "iand(a, b) -- Same as a &= b.")
spam2(ixor,__ixor__, "ixor(a, b) -- Same as a ^= b.")
spam2(ior,__ior__, "ior(a, b) -- Same as a |= b.")
spam2(concat,__concat__,
"concat(a, b) -- Same as a + b, for a and b sequences.")
spam2(repeat,__repeat__,
"repeat(a, b) -- Return a * b, where a is a sequence, and b is an integer.")
spam2(iconcat,__iconcat__,
"iconcat(a, b) -- Same as a += b, for a and b sequences.")
spam2(irepeat,__irepeat__,
"irepeat(a, b) -- Same as a *= b, where a is a sequence, and b is an integer.")
spam2(getitem,__getitem__,
"getitem(a, b) -- Same as a[b].")
spam2(setitem,__setitem__,
@ -235,6 +274,7 @@ spam2(setitem,__setitem__,
spam2(delitem,__delitem__,
"delitem(a, b) -- Same as del a[b].")
spam2(pow,__pow__, "pow(a, b) -- Same as a ** b.")
spam2(ipow,__ipow__, "ipow(a, b) -- Same as a **= b.")
spam2(getslice,__getslice__,
"getslice(a, b, c) -- Same as a[b:c].")
spam2(setslice,__setslice__,