2016-11-03 32 views
5

Chciałbym zrobić:Czy można zastąpić zachowanie%% za pomocą __rmod__?

x %doSomething% y 

co jest dość łatwe do zrobienia (patrz poniższy kod) dla dowolnego x i y dowolnej wyjątkiem, że X jest ul.

Czy jest jakiś sposób (np. Dodanie specjalnej metody lub podniesienie określonego błędu), aby spowodować, że formatowanie starego stylu zakończy się niepowodzeniem (podobnie jak 1% DoSomthing kończy się niepowodzeniem z TypeError) i powrócić do metody __rmod__ zdefiniowanej w doSomething obiekt?

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

Aby wyjaśnić: Chcesz '" foo "% doSomething%" pasek "', aby zwrócić '" foobar "'? Wierzę, że to niemożliwe, ponieważ 'str .__ mod__' podnosi' TypeError' zamiast zwracania 'NotImplemented'. – L3viathan

+0

@MartijnPieters Nie widzę, żeby to działało z twoją odpowiedzią. Działa na liczbach całkowitych itp., Jak w pytaniu, ale '' foo "% doSomething%" bar "' podnosi ten sam TypeError. – L3viathan

+0

@ L3viathan: nie, byłem tu trochę za daleko. W rzeczywistości jest to błąd w Pythonie. –

Odpowiedz

7

Uwaga: złożyłam poprawki dla Pythona 2.7 i 3.5 i wyżej. Te wylądowały i są częścią 2.7.14, 3.5.4, 3.6.1 i 3.7, gdzie przykład OP działa teraz zgodnie z oczekiwaniami. W przypadku starszych wersji, patrz poniżej.


Niestety, nie jest to obecnie możliwe w Pythonie. Zachowanie się sztywno w pętli oceny:

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

(Z Python 3.5 source code, gdzie PyUnicode jest typem Pythona str).

Jest to niefortunne, ponieważ dla każdy inny rodzaj można zapobiec metodę LHS.__mod__ się powoływać przy użyciu podklasy dla argumentu po prawej stronie; z documentation:

Uwaga: Jeśli typ prawy argument jest podklasą typu lewy operand i że podklasa stanowi odzwierciedlenie sposobu działania, ta metoda zostanie wywołana przed zakaz odzwierciedlenie lewy argument na metoda. To zachowanie pozwala podklasom zastąpić operacje ich przodków.

To byłaby jedyna opcja tutaj, str % other nigdy nie powraca NotImplemented, wszystkie rodzaje RHS są akceptowane (rzeczywista str.__mod__ method akceptuje tylko str obiektów dla RHS, ale nie nazywa się w tym przypadku).

Uważam, że jest to błąd w Pythonie, zgłoszony jako issue #28598.

+0

Thx. Bardzo miło mieć ostateczną odpowiedź. – DangerMouse

+0

Thx to L3viathan za początkowe wskazywanie problemu i MartijnPieters na wykopywanie i inicjowanie ścieżki błędów. Moje wybrane obejście polega na użyciu '__mul__' i' __rmul__', więc 'result = 4 * plus * 5' – DangerMouse