2016-11-03 2 views
5

Я хотел бы сделать:Можно ли перезаписать поведение str str с помощью __rmod__?

x %doSomething% y 

, который достаточно легко сделать (см код ниже) для любых х и у любого, кроме как в случае, когда х является ул.

Есть ли какой-либо способ (например, добавление специального метода или повышение определенной ошибки), чтобы вызвать форматирование строки старого стиля (аналогично тому, как 1% doSomthing терпит неудачу с TypeError) и вернуться к методу __rmod__, определенному в doSomething объект?

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 
+2

Чтобы уточнить: вы хотите '" foo "% doSomething%" bar "' возвращать '" foobar "'? Я считаю, что это невозможно, потому что 'str .__ mod__' вызывает' TypeError' вместо возврата 'NotImplemented'. – L3viathan

+0

@MartijnPieters Я не вижу, что работаю с вашим ответом. Он работает для целых чисел и т. Д., Как в вопросе, но '' foo "% doSomething%" bar "' вызывает тот же TypeError. – L3viathan

+0

@ L3viathan: Нет, я был здесь слишком далеко. На мой взгляд, это на самом деле ошибка в Python. –

ответ

7

Примечание: Я представил патчи для Python 2.7 и 3.5 и выше. Они высадились и являются частью 2.7.14, 3.5.4, 3.6.1 и 3.7, где пример OP теперь работает так, как ожидалось. Для более старых версий см. Ниже.


К сожалению, на данный момент это невозможно в Python. Поведение зашиты в цикле оценки:

TARGET(BINARY_MODULO) { 
    PyObject *divisor = POP(); 
    PyObject *dividend = TOP(); 
    PyObject *res = PyUnicode_CheckExact(dividend) ? 
     PyUnicode_Format(dividend, divisor) : 
     PyNumber_Remainder(dividend, divisor); 

Python 3.5 source code, где PyUnicode является типом Python str).

Это печально, потому что для любых другого типа вы можете предотвратить метод LHS.__mod__ быть вызван с использованием подкласса для правого операнда; от documentation:

Примечания: Если выбран типа правого операнда является подклассом типа левого операнда и тот подкласс обеспечивает отраженный метод для операции, этот метод будет вызываться перед Неотраженные левый операнд метод. Такое поведение позволяет подклассам переопределять операции своих предков.

Это был бы единственным вариантом здесь, str % other никогда не возвращается NotImplemented, всех типов RHS принимаются (фактическая str.__mod__ method принимает только str объекты для РИТ, но не называются в данном случае).

Я считаю это ошибкой в ​​Python, поданной как issue #28598.

+0

Thx. Очень приятно иметь окончательный ответ. – DangerMouse

+0

Thx to L3viathan, изначально указывающий на проблему, и MartijnPieters для поиска и инициирования трека ошибок. Мое выбранное решение - использовать '__mul__' и' __rmul__', таким образом 'result = 4 * plus * 5' – DangerMouse