I'd like to do:
x %doSomething% y
which is easy enough to do (see code below) for any x and any y except in the case that x is a str.
Is there any way (e.g. adding a special method or raising a specific error) to cause old style string formatting to fail (similarly to how 1 %doSomthing fails with a TypeError) and revert to the __rmod__ method defined in the doSomething object?
class BinaryMessage(object):
def __init__(self, fn):
self._fn = fn
def __rmod__(self, LHS):
return BinaryMessagePartial(self._fn, LHS)
class BinaryMessagePartial(object):
def __init__(self, fn, LHS):
self._fn = fn
self._LHS = LHS
def __mod__(self, RHS):
return self._fn(self._LHS, RHS)
def _doSomething(a , b):
return a + b
doSomething = BinaryMessage(_doSomething)
result = 5 %doSomething% 6
assert result == 11
Note: I submitted patches for Python 2.7, and 3.5 and up. These have landed and are part of 2.7.14, 3.5.4, 3.6.1 and 3.7, where the OP example now works as expected. For older versions, see below.
Unfortunately, this is not currently possible in Python. The behaviour is hardcoded in the evaluation loop:
TARGET(BINARY_MODULO) {
PyObject *divisor = POP();
PyObject *dividend = TOP();
PyObject *res = PyUnicode_CheckExact(dividend) ?
PyUnicode_Format(dividend, divisor) :
PyNumber_Remainder(dividend, divisor);
(From the Python 3.5 source code, where PyUnicode
is the Python str
type).
This is unfortunate, because for every other type you can prevent the LHS.__mod__
method to be invoked by using a subclass for the right-hand operand; from the documentation:
Note: If the right operand’s type is a subclass of the left operand’s type and that subclass provides the reflected method for the operation, this method will be called before the left operand’s non-reflected method. This behavior allows subclasses to override their ancestors’ operations.
This would have been the only option here, str % other
never returns NotImplemented
, all RHS types are accepted (the actual str.__mod__
method only accepts str
objects for the RHS, but is not called in this case).
I consider this a bug in Python, filed as issue #28598.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With