2010-11-17 9 views
9

en Python podemos decir:¿qué métodos realmente invocan `foo <bar <baz`?

if foo < bar < baz: 
    do something. 

y de manera similar, podemos sobrecargar los operadores COMPARACIÓN como:

class Bar: 
    def __lt__(self, other): 
     do something else 

pero lo que los métodos de los tipos de los operandos de las comparaciones de intervalo se llama en realidad? es equivalente a la anterior

if foo.__lt__(bar) and bar.__lt__(baz): 
    do something. 

Edición: Re S. Lott, He aquí alguna salida que ayuda a ilustrar lo que realmente sucede.

>>> class Bar: 
    def __init__(self, name): 
     self.name = name 
     print('__init__', self.name) 
    def __lt__(self, other): 
     print('__lt__', self.name, other.name) 
     return self.name < other.name 

>>> Bar('a') < Bar('b') < Bar('c') 
('__init__', 'a') 
('__init__', 'b') 
('__lt__', 'a', 'b') 
('__init__', 'c') 
('__lt__', 'b', 'c') 
True 
>>> Bar('b') < Bar('a') < Bar('c') 
('__init__', 'b') 
('__init__', 'a') 
('__lt__', 'b', 'a') 
False 
>>> 
+0

+1: Usted podría (y sí) respondió tu propia pregunta. -1: Ciertamente no necesita preguntar esto aquí, ya que encontrar la respuesta fue claramente más fácil y rápido que preguntar. –

Respuesta

4

Estás en lo correcto:

class Bar: 
    def __init__(self, name): 
     self.name = name 
    def __lt__(self, other): 
     print('__lt__', self.name, other.name) 
     return True 

a,b,c = Bar('a'), Bar('b'), Bar('c') 

a < b < c 

salida :

('__lt__', 'a', 'b') 
('__lt__', 'b', 'c') 
True 
+0

hasta cierto punto, también estoy muy interesado en si 'y' está siendo utilizado, o si está sucediendo alguna otra cosa inteligente. – SingleNegationElimination

+0

Con algunas pruebas, parece que debe hacer algo esencialmente similar. Puedo hacer que la segunda comparación sea cortocircuitada haciendo que la primera sea falsa. – SingleNegationElimination

+0

@TokenMacGuy: Como puede ver en mi segundo ejemplo, es un poco más que simple y, como la barra puede ser una función mutante. –

12
if foo < bar < baz: 

es equivalente a

if foo < bar and bar < baz: 

con una diferencia importante: si la barra es un mutante, que se almacenan en caché. Es decir:

if foo < bar() < baz: 

es equivalente a

tmp = bar() 
if foo < tmp and tmp < baz: 

Pero para responder a su pregunta, que va a terminar siendo:

if foo.__lt__(bar) and bar.__lt__(baz): 
+0

Guau, las primeras tres líneas de mi publicación iban a ser las mismas que las suyas, excepto un solo punto. +1 a ti. ;) –

1

llama al método especial __lt__(), y si es necesario se llamará __nonzero__() para coaccionar el resultado de __lt__() a un valor lógico. Sorprendentemente (para mí al menos), no hay un método __and__() para anular el operador and.

Aquí es un programa de prueba:

#!/usr/bin/env python 

class Bar: 
    def __init__(self, value): 
     self.value = value 

    def __lt__(self, other): 
     print "%s.__lt__(%s)" % (self, other) 
     return Bar("%s.__lt__(%s)" % (self, other)) 

    def __nonzero__(self): 
     print "%s.__nonzero__()" % (self) 
     return True 

    def __str__(self): 
     return self.value 

foo = Bar("foo") 
bar = Bar("bar") 
baz = Bar("baz") 

if foo < bar < baz: 
    pass 

Salida:

foo.__lt__(bar) 
foo.__lt__(bar).__nonzero__() 
bar.__lt__(baz) 
bar.__lt__(baz).__nonzero__() 
+0

'y' no es un operador en este contexto, es un mecanismo para describir el flujo de control (obviamente en otro contexto hay un' y 'bit a bit, para el cual hay un operador apropiado y una anulación' __and__'). Tenga en cuenta que 'y' en realidad no compara nada, simplemente evalúa la veracidad de cada miembro de la expresión, y cuando encuentra uno que es falso, rescata. Pedir un método para anular 'y' es como pedir un método para anular 'si'. –

3

Utiliza sucesivas llamadas al operador menos que la comparación:

>>> import dis 
>>> def foo(a,b,c): 
...  return a < b < c 
... 
>>> dis.dis(foo) 
    2   0 LOAD_FAST    0 (a) 
       3 LOAD_FAST    1 (b) 
       6 DUP_TOP    
       7 ROT_THREE   
       8 COMPARE_OP    0 (<) 
      11 JUMP_IF_FALSE   8 (to 22) 
      14 POP_TOP    
      15 LOAD_FAST    2 (c) 
      18 COMPARE_OP    0 (<) 
      21 RETURN_VALUE   
     >> 22 ROT_TWO    
      23 POP_TOP    
      24 RETURN_VALUE   
+0

+1 para el código generado. Esto simplemente refuerza que la sintaxis corta que había planeado para una clase no ocurrirá de manera segura. Pero aprendí tanto que valía la pena investigarlo. – SingleNegationElimination

Cuestiones relacionadas