Is it possible to overwrite str% behavior with __rmod__?

I would like to:

x %doSomething% y 

which is easy enough to do (see code below) for any x and any y, except when x is str.

Is there any way (for example, adding a special method or raising a specific error) to make formatting an old-style string fail (similar to how 1% doSomthing fails with TypeError) and return 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 
+5
source share
1 answer

Note I sent patches for Python 2.7 and 3.5 and above. They 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 currently not possible in Python. The behavior is hard-coded 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 source code of Python 3.5 , where PyUnicode is a type of Python str ).

This is unsuccessful because for every other type you can disable the LHS.__mod__ method using a subclass for the right operand; from the documentation :

Note If the type of regular operands is a subclass of the type of left operands, and this subclass provides a reflected method for the operation, this method will be called before the left operand without a reflected method. This behavior allows subclasses to redefine the operations of their ancestors.

This would be the only option here, str % other never returns NotImplemented , all RHS types are accepted (the actual str.__mod__ method accepts only str objects for RHS, but in this case it is not called).

I believe this is a bug in Python registered as issue # 28598 .

+7
source

Source: https://habr.com/ru/post/1259221/


All Articles