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 .
source share