2010-09-21 9 views
8

Nigdy wcześniej nie operowałem operatorami odwrotnymi, więc proszę nie płonąć! Właśnie skończyłem się uczyć o nich, więc chciałem je wypróbować. Ale z jakiegoś powodu nie działa. Oto kod:Używanie operatorów odwrotnych w Pythonie

>>> class Subtract(object): 
    def __init__(self, number): 
     self.number = number 
    def __rsub__(self, other): 
     return self.number - other.number 


>>> x = Subtract(5) 
>>> y = Subtract(10) 
>>> x - y   # FAILS! 

Traceback (most recent call last): 
    File "<pyshell#8>", line 1, in <module> 
    x - y 
TypeError: unsupported operand type(s) for -: 'Subtract' and 'Subtract' 
>>> x.__rsub__(y) # WORKS! 
-5 

Jeśli zmienię __rsub__ do __sub__, to działa.

Co robię źle? Jaki jest cel tych operatorów odwrotnych?

Odpowiedz

4

__rsub__() zostanie wywołany tylko wtedy, gdy operandy są różnych typów; gdy są tego samego typu, zakłada się, że jeśli nie ma __sub__, nie można ich odjąć.

Należy również pamiętać, że logika jest odwrotna w każdym przypadku; wracasz samo - inne zamiast drugiej - samo

+0

Ale w jaki sposób działa wywołanie '__rsub__'? – Randy

+0

Ponieważ '__rsub__' jest zdefiniowaną funkcją i można ją nazwać jak każdą inną funkcję; po prostu nie będzie automatycznie wywoływany do implementacji operatora '-'. – geoffspear

+0

@Randy: Ponieważ kiedy nazywasz to jawnie, jest to zwykła metoda. Dlaczego miałbyś oczekiwać, że to nie zadziała? Jedyną rzeczą wyróżniającą '__rsub__' jest to, że w pewnych okolicznościach Python przetłumaczy operację odejmowania' - 'na wywołanie' __rsub__' - ale jak wyjaśniono w odpowiedziach, te pewne okoliczności nie występują w twój przykład. –

2

methods with reflected operands są tak, że klasa może implementować operator gdy lewy argument jest prymitywne lub coś innego, co nie jest pod kontrolą:

These functions are only called if the left operand does not support the corresponding operation and the operands are of different types.

Ponieważ oba są tego samego typu, tchórzliwie odmawiają i należy zastosować metodę __sub__.

3

Od modelu danych Pythona na http://docs.python.org/reference/datamodel.html:

These methods are called to implement the binary arithmetic operations (+, -, *, /, %, divmod(), pow(), **, <<, >>, &, ^, |) with reflected (swapped) operands. These functions are only called if the left operand does not support the corresponding operation and the operands are of different types. [2] For instance, to evaluate the expression x - y, where y is an instance of a class that has an __rsub__() method, y.__rsub__(x) is called if x.__sub__(y) returns NotImplemented.

Jednak - oba obiekty nie muszą być tej samej klasy - co oznacza, że ​​nawet jeśli umieścić metodę __sub__ zawracania NotImplemented na powyższym przykładzie, będziesz nadal otrzymuję ten sam błąd: Python zakłada, że ​​twoja klasa Subtract nie może odjąć od "Subtract" iobjects, bez względu na kolejność.

Jednak to działa:

class Sub1(object): 
    number = 5 
    def __sub__(self, other): 
     return NotImplemented 

class Sub2(object): 
    number = 2 
    def __rsub__(self, other): 
     return other.number - self.number 


a = Sub1() 
b = Sub2() 

print a - b 
3

Punktem tych metod jest umożliwienie w ten sposób:

class MyNumber(object): 
    def __init__(self, x): 
     self.x = x 

print 10 - MyNumber(9) # fails because 10.__sub__(MyNumber(9)) is unknown 

class MyFixedNumber(MyNumber): 
    def __rsub__(self, other): 
     return MyNumber(other - self.x) 

print 10 - MyFixedNumber(9) # MyFixedNumber(9).__rsub__(10) is defined 

Bardzo rzadko przydatnych choć zwykle po prostu używać rzeczy tego samego rodzaju i bezpośredni __sub__

Powiązane problemy