2009-06-30 4 views
24

Przeglądając decimal.py, używa on NotImplemented w wielu specjalnych metodach. na przykładPython niezmodyfikowany stała

class A(object): 
    def __lt__(self, a): 
     return NotImplemented 

    def __add__(self, a): 
     return NotImplemented 

Python docs say:

NotImplemented

wartość specjalne, które mogą zostać zwrócone przez „bogate porównania” metod specjalnych (__eq__(), __lt__(), i znajomych), aby wskazać, porównanie nie jest zaimplementowane z względem drugiego typu.

Nie mówi o innych specjalnych metodach i nie opisuje zachowania.

Wydaje się, że jest to magiczny obiekt, który po zwrocie z innych specjalnych metod podnosi TypeError, a w "bogatym porównaniu" specjalne metody nic nie robią.

np.

print A() < A() 

drukuje True, ale

print A() + 1 

podnosi TypeError, więc jestem ciekaw, co się dzieje i co jest wykorzystanie/zachowanie NotImplemented.

+2

Wszystko poprawnie. Całkowicie opisałeś NotImplemented. Jakie jest pytanie? –

+0

moje pytanie brzmiało, że jeśli w dokumencie, to specjalnie wymienia specjalne metody "bogatego porównania", inne metody powinny je ignorować, w końcu to tylko kolejny obiekt, nie mogłem znaleźć dokumentu wyjaśniającego ogólne zachowanie lub jak radzić sobie z NotImplemented –

Odpowiedz

26

NotImplemented pozwala wskazać, że porównanie dwóch podanych operandów nie zostało zaimplementowane (zamiast wskazywać, że porównanie jest prawidłowe, ale daje False, dla dwóch argumentów).

Z Python Language Reference:

dla obiektów xiy, najpierw x.__op__(y) się starał. Jeśli to nie zostanie zaimplementowane, to zostanie wypróbowany lub zwrot niezmawiający, y.__rop__(x). Jeśli ta wartość również nie zostanie zaimplementowana lub nie zostanie wprowadzona NotImplemented, zostanie zgłoszony wyjątek TypeError . Ale patrz poniższy wyjątek:

Wyjątkiem poprzedniego pozycji: jeśli lewy argument jest instancją wbudowanego typu lub klasy nowy styl i prawego operandu jest instancją Prawidłowa podklasa danego typu lub klasy i nadpisuje __rop__() metodę bazowej , __rop__() metoda prawo operand jest wypróbowany przed __op__() metody lewy argument za. Dzieje się to tak, że podklasa może całkowicie zastąpić operatorów binarnych .W przeciwnym wypadku, lewy argument operand musiałby zaakceptować prawy operand: gdy oczekiwane jest wystąpienie danej klasy, , instancja podklasy tej klasy jest zawsze akceptowalna.

+3

ok, więc ogólne zachowanie polega na tym, że jeśli zwracana jest wartość niezatwierdzona, spróbuj czegoś innego, jeśli nie jest to możliwe, podnieś TypeError –

+0

Czy nie jest dobrym pomysłem użycie go w innych kontekstach, jak na przykład mapowanie słownika między różnymi typami? – endolith

4

To rzeczywiście ma takie samo znaczenie, gdy są zwracane z __add__ począwszy od __lt__, różnica jest Python 2.x próbuje innych sposobów porównywania obiektów przed poddaniem się. Python 3.x wywołuje TypeError. W rzeczywistości, Python może wypróbować inne rzeczy również dla __add__, spójrz na __radd__ i (choć jestem na nim rozmyta) __coerce__.

# 2.6 
>>> class A(object): 
... def __lt__(self, other): 
...  return NotImplemented 
>>> A() < A() 
True 

# 3.1 
>>> class A(object): 
... def __lt__(self, other): 
...  return NotImplemented 
>>> A() < A() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unorderable types: A() < A() 

Aby uzyskać więcej informacji, zobacz Ordering Comparisions (3.0 docs).

0

Jeśli zwrócisz go z __add__, będzie zachowywać się tak, jak obiekt nie ma metody __add__ i podnieść TypeError.

Jeśli zwrócisz NotImplemented z funkcji porównania bogatego, Python będzie zachowywał się tak, jak metoda nie została zaimplementowana, to znaczy, że będzie odraczał używanie __cmp__.