2010-11-17 14 views
9

in Python possiamo dire:quali metodi effettivamente invoca? Foo <bar <baz`?

if foo < bar < baz: 
    do something. 

e allo stesso modo, siamo in grado di sovraccaricare gli operatori confronto come:

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

ma quali metodi dei tipi degli operandi di queste comparazioni intervallo sono effettivamente chiamati? è il precedente equivalente a

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

Modifica: re S.Lott, Ecco alcuni output che aiutano a illustrare ciò che effettivamente accade.

>>> 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: Si potrebbe (e fatto) rispondere alla tua stessa domanda. -1: Di certo non dovevi chiederlo qui, dal momento che trovare la risposta era chiaramente più facile e veloce che chiedere. –

risposta

4

Lei ha ragione:

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 

uscita :

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

in una certa misura, sono anche molto interessato a se 'e' viene utilizzato, o qualcosa di intelligente sta succedendo. – SingleNegationElimination

+0

Con alcuni test, sembra che debba fare qualcosa di sostanzialmente simile. Posso fare in modo che il secondo confronto sia cortocircuitato facendo sì che il primo sia falso. – SingleNegationElimination

+0

@TokenMacGuy: Come puoi vedere nel mio secondo esempio, è un po 'più di un semplice e, dato che la barra potrebbe essere una funzione di muting. –

12
if foo < bar < baz: 

è equivalente a

if foo < bar and bar < baz: 

con una distinzione importante: se bar è un mutante, che verrà memorizzata nella cache. Vale a dire:

if foo < bar() < baz: 

equivale a

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

Ma per rispondere alla tua domanda, finirà per essere:

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

Wow, le prime tre righe del mio post sarebbero state le stesse del tuo, tranne un singolo due punti. +1 a te. ;) –

1

chiama il metodo speciale __lt__(), e, se necessario, si chiamerà __nonzero__() di costringere il risultato di __lt__() ad un valore booleano. Sorprendentemente (almeno per me), non esiste il metodo __and__() per ignorare l'operatore and.

Ecco un programma di test:

#!/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 

uscita:

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

'and' non è un operatore in questo contesto, è un meccanismo per descrivere il flusso di controllo (ovviamente in un altro contesto c'è un bit' and', per il quale esiste un operatore appropriato e un override '__and__'). Tieni presente che 'e' in realtà non confronta nulla, valuta solo ciascun membro dell'espressione per la verità, e quando ne trova uno falso lo mette in guardia. Chiedere un metodo per sovrascrivere 'e' è come chiedere un metodo per sovrascrivere' if'. –

3

Esso utilizza le chiamate successive per l'operatore minore di confronto:

>>> 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 per codice generato. Questo semplicemente rafforza il fatto che la sintassi tagliente che avevo programmato per una lezione non avverrà in modo sicuro. Ma ho imparato così tanto che valeva la pena di esaminarlo. – SingleNegationElimination

Problemi correlati