2010-09-21 7 views
8

Nunca antes he manejado operadores inversos, ¡por favor no llame! Acabo de terminar de aprender sobre ellos, así que quería probarlos. Pero por alguna razón, no está funcionando. Aquí está el código:Uso de operadores inversos en Python

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

Si cambio __rsub__-__sub__, funciona.

¿Qué estoy haciendo mal? ¿Cuál es también el propósito de estos operadores inversos?

Respuesta

4

__rsub__() solo se invocarán si los operandos son de tipos diferentes; cuando son del mismo tipo, se supone que si __sub__ no está presente, no pueden restarse.

También tenga en cuenta que su lógica se invierte en cualquier caso; usted está volviendo auto - otra vez de otra - auto

+0

¿Pero cómo funciona explícitamente el llamado '__rsub__'? – Randy

+0

Porque '__rsub__' es una función que definió y puede llamarla como cualquier otra función; simplemente no se llamará automáticamente para implementar el operador '-'. – geoffspear

+0

@Randy: Porque cuando lo llamas explícitamente, es solo un método regular. ¿Por qué esperarías que no funcionara? Lo único especial sobre '__rsub__' es que bajo ciertas circunstancias, Python traducirá una operación de resta' - 'en una llamada a' __rsub__' - pero como se explica en las respuestas, esas ciertas circunstancias no están presentes en tu ejemplo –

2

El methods with reflected operands se proporcionan para que su clase puede implementar un operador cuando el operando de la izquierda es una primitiva u otra cosa que no está bajo su control:

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

Dado que son del mismo tipo, es un rechazo cobarde y debe implementar el método __sub__.

3

A partir del modelo de datos de Python en 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.

Sin embargo - ambos objetos no deben ser de la misma clase - que quiere decir, que incluso si se pone un método __sub__ Volviendo NotImplemented en el ejemplo anterior, se quiere todavía recibe el mismo error: Python solo asume que su clase de Restar no puede restar de los objetos "Resta", sin importar el orden.

Sin embargo, esto funciona:

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

El punto de estos métodos es permitir esto:

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 

Muy rara vez son útiles, sin embargo, por lo general sólo tiene que utilizar cosas que son del mismo tipo y de la directa __sub__