Nie można zagwarantować, że dwa obiekty będą miały taką samą wartość, chyba że będą porównywać równe [1].
Funkcje języka Python (w tym lambdy) nie są równe, nawet jeśli mają identyczny kod [2]. Na przykład:
>>> (lambda: 1) == (lambda: 1)
False
Wdrożenie to zachowanie wynika z faktu, że obiekty funkcji nie zapewniają własnego operatora równości. Zamiast tego dziedziczą domyślną, która używa tożsamości obiektu, tj. Jego adresu. Od documentation:
Jeśli nie __cmp__()
, __eq__()
lub __ne__()
eksploatacja jest określona, klasa przypadki są porównywane przez tożsamość obiektu („adres”).
Oto, co dzieje się w danym przykładzie:
fn = lambda: 1 # New function is allocated at address A and stored in fn.
fn = lambda: 1 # New function is allocated at address B and stored in fn.
# The function at address A is garbage collected.
fn = lambda: 1 # New function is allocated at address A and stored in fn.
# The function at address B is garbage collected.
fn = lambda: 1 # New function is allocated at address B and stored in fn.
# The function at address A is garbage collected.
...
Ponieważ adres A
zawsze jest mieszany do jednej wartości, a zająć B
do drugiego, widzisz hash(fn)
zastępcę pomiędzy tymi dwiema wartościami. To naprzemienne zachowanie jest jednak artefaktem implementacji i może zmienić jeden dzień, jeśli na przykład, garbage collector będzie zachowywał się nieco inaczej.
Poniższy wnikliwa uwaga zostało wniesione przez @ruakh:
Warto zauważyć, że nie jest możliwe, aby napisać ogólny proces określania, czy dwie funkcje są równoważne. (Jest to konsekwencją undecidability z halting problem.) Ponadto dwie funkcje Python może zachowywać się inaczej, nawet jeśli ich kod jest identyczna (ponieważ mogą one być zamknięcia nawiązujące do odrębny-but-identycznie nazwanych zmiennych). Ma więc sens, że funkcje Pythona nie przeciążają operatora równości: nie ma możliwości, aby zaimplementować coś lepszego niż domyślne porównanie obiektu.
[1] Odwrotność na ogół nie jest prawdziwa: dwa obiekty, które nie mają sobie równych, mogą mieć tę samą wartość skrótu. Nazywa się to hash collision.
[2] Wywołanie swoje lambdy a następnie mieszania wynik byłby oczywiście zawsze dają taką samą wartość, ponieważ hash(1)
jest zawsze taka sama w obrębie jednego programu:
>>> (lambda: 1)() == (lambda: 1)()
True
Żeby było jasne, zdajesz sobie sprawę, że mieszkasz w samym obiekcie funkcji, nie mieszając wartości, która powróciłaby po wywołaniu, prawda? –
To prawdopodobnie zły pomysł, ale można po prostu wziąć pod uwagę obiekt kodu: 'hash ((lambda: 1) .__ kod __)' – berdario
po prostu ciekawy ... do jakich modeli potrzebowałbyś tej funkcji? czy często wyszukiwane są w słownikach w oparciu o dowolną funkcję? –