2009-08-09 12 views
45

To byłoby podobne do metody java.lang.Object.hashcode().Czy istnieje unikalny identyfikator obiektu w Pythonie

Potrzebuję przechowywać obiekty, których nie kontroluję w zestawie, i upewnić się, że tylko wtedy, gdy dwa obiekty są faktycznie tym samym obiektem (nie zawierają tych samych wartości), wartości zostaną nadpisane.

+5

Zauważ, że 'hashCode()' w Javie niekoniecznie jest wyjątkowy, to tylko jedne starannie dobrane semantyka w połączeniu z 'equals()'. – Joey

+0

I tak jak napisano poniżej, 'hash()' ma ** dokładnie ** tę samą semantykę co 'java.lang.Object.hashcode()'. –

Odpowiedz

70
id(x) 

zrobi za Ciebie. Ale jestem ciekawy, co jest nie tak z zestawem obiektów (który łączy obiekty według wartości)?

Dla twojego konkretnego problemu prawdopodobnie zachowałbym zestaw identyfikatorów lub obiektów opakowania. Obiekt opakowania będzie zawierał jedno odniesienie i porówna je przez: x==y < ==>x.ref is y.ref.

Warto również zauważyć, że obiekty Pythona mają również funkcję hash. Ta funkcja jest niezbędna, aby umieścić obiekt w zestawie lub słowniku. Czasami zdarza się, że zderzają się z różnymi obiektami, ale dobre implementacje z hash starają się zmniejszyć prawdopodobieństwo.

+1

Głosowanie w dół, ponieważ id (x) nie zapewnia unikalności dla każdego obiektu. OP był bardzo jasny, że chce traktować różne obiekty zawierające tę samą wartość, by były * inne *. – Roy

+2

@Roy wręcz przeciwnie [docs] (https://docs.python.org/2/library/functions.html#id) mówią, że 'id (x)' _is_ "gwarantowane jest unikalne i stałe dla tego obiektu podczas jego trwania ", co spowodowałoby, że różne obiekty o tej samej wartości miałyby różne identyfikatory (o ile obie istniały jednocześnie), co umożliwiłoby OP robienie tego, co chcieli. – sparrowt

+0

@sparrowt Widzę. Zgadzam się z tobą.Kluczową kwestią jest to, że "identyfikator musi być unikalny *, gdy dwa obiekty o tej samej wartości współistnieją *". 'id()' wydaje się zwracać ten sam identyfikator dla wielokrotnie tworzonych (i niszczonych) obiektów o tej samej wartości, stąd mój oryginalny komentarz, ale w rzeczywistości jest to w porządku, ponieważ OP stwierdził, że identyfikatory muszą być unikalne, gdy obiekty współistnieją. Usuwam moje głosowanie. – Roy

18

Po to jest "is".

zamiast badań "if a == b", który testuje dla tej samej wartości,

test "if a is b", który będzie testem dla tego samego identyfikatora.

+17

Czy byłoby właściwe powiedzieć, że "jest" w Pythonie jak "==" Javy, a "==" w języku Pythona jest jak "równa się()" Javy? – MatrixFrog

+9

@MatrixFrog Tak. – Imagist

1

Jak wspomniano, id (x) tworzy niepowtarzalny identyfikator obiektu.

Ale twoje pytanie jest mylące, ponieważ metoda hashCode Java nie daje unikalnego identyfikatora. Kod asocjacyjny języka Java działa podobnie do większości funkcji mieszania: zawsze zwraca tę samą wartość dla tego samego obiektu, dwa obiekty, które są równe, zawsze otrzymują równe kody, a nierówne wartości mieszające oznaczają nierówne kody skrótu. W szczególności dwa różne i nierówne obiekty mogą uzyskać tę samą wartość.

To jest mylące, ponieważ kryptograficzne funkcje mieszające różnią się od tego i przypominają (choć nie do końca) "unikalny identyfikator", o który prosiłeś.

Pythonowym odpowiednikiem metody hashCode języka Java jest hash (x).

+0

Dlatego właśnie wyraźnie wspomniałem metodę hashcode java.lang.Object. Który domyślnie tworzy unikalny long dla tego obiektu. Rozumiem, że inne implementacje kodu skrótu mogą i są różne. – oneself

+0

Ale o to właśnie chodzi: hashCode nie generuje unikalnej długości. Wytwarza długie, które starają się nie kolidować, ale nie możesz mapować strun do długich i wytworzyć unikalnej wartości. –

+1

... i stary wątek, który znam. Ale chciałem zwrócić uwagę, że id() jest wyjątkowy tylko wtedy, gdy oba obiekty nadal istnieją. Po uwolnieniu identyfikator może zostać przypisany do innego obiektu na "Dwa obiekty z nienakładającymi się okresami życia mogą mieć tę samą wartość id()." [link] (https://docs.python.org/2/library/functions.html#id) –

-1

Nie musisz porównywać obiektów przed umieszczeniem ich w zestawie. semantyka set() już to zajmuje.

class A(object): 
    a = 10 
    b = 20 
    def __hash__(self): 
     return hash((self.a, self.b)) 

    a1 = A() 
    a2 = A() 
    a3 = A() 
    a4 = a1 
    s = set([a1,a2,a3,a4]) 
    s 
=> set([<__main__.A object at 0x222a8c>, <__main__.A object at 0x220684>, <__main__.A object at 0x22045c>]) 

Uwaga: Naprawdę nie trzeba zastąpić hash udowodnić to zachowanie :-)

+1

Twoje rozwiązanie zależy od rodzaju klasy odziedziczonej po: 'class B (str): pass' if called z 'set ([B(), B()])' prowadzi do 'set ([''])'. Identyfikacja ze słowników zwykle niejawnie zależy od "id (x)" dla obiektów, powinieneś po prostu użyć go jawnie i unikać przypadków narożnych. – Arne

+0

@ArneRecknagel masz rację. ale co byś włożył do zestawu po sprawdzeniu id (x)? – user942640

Powiązane problemy