Чи є в Python унікальний ідентифікатор об’єкта


79

Це було б схоже на java.lang.Object.hashcode()метод.

Мені потрібно зберігати об’єкти, над якими я не маю контролю, у наборі, і переконайтесь, що лише якщо два об’єкти насправді є однаковим об’єктом (не містять однакових значень), значення будуть перезаписані.


6
Зауважте, що hashCode()Java не обов’язково унікальна, вона лише має дещо ретельно підібрану семантику разом із equals().
Джої

1
І як розміщено нижче, Python hash()має точно таку ж семантику, як java.lang.Object.hashcode().
ілля н.

Відповіді:


128
id(x)

зробить трюк за вас. Але мені цікаво, що не так у наборі об’єктів (який об’єднує об’єкти за значенням)?

Для вашої конкретної проблеми я б, мабуть, зберіг набір ідентифікаторів або об'єктів-обгортки. Об'єкт-обгортка буде містити одне посилання та порівнювати за x==y<==>x.ref is y.ref .

Також варто зазначити, що об’єкти Python також мають свою hashфункцію. Ця функція необхідна для розміщення об'єкта в наборі або словнику. Передбачається, що іноді стикаються з різними об'єктами, хоча хороші реалізації hashнамагаються зробити це менш імовірним.


3
Голосування проти, оскільки id (x) не переконує в унікальності кожного об’єкта. OP було ясно , що він / вона хоче , щоб розглядати різні об'єкти , що містять однакове значення , щоб бути різними .
Рой

12
@Roy, навпаки, документи говорять , що id(x) це «гарантовано бути унікальним і постійним для даного об'єкта в протягом його життя» , яке привело б до різних об'єктів з тим же значенням , що мають різні ідентифікатори ( до тих пір , як вони обидва існують одночасно) , який дозволить ОП робити те, що вони хотіли.
воробей

3
@sparrowt я бачу. Я згоден з вами. Ключовим моментом є те, що "ідентифікатор повинен бути унікальним, коли два об'єкти з однаковим значенням співіснують ". id()здається, повертає той самий ідентифікатор для неодноразово створених (і знищених) об'єктів з однаковим значенням, звідси мій оригінальний коментар, але насправді це нормально, оскільки OP заявив, що ідентифікатори повинні бути унікальними, коли об'єкти співіснують. Видалення мого голосу проти.
Рой

Ах, не можу змінити свій голос зараз, занадто пізно. Вибачте за плутанину та неправильне голосування (чесна помилка).
Рой

1
@ flow2k x.refу цьому випадку буде іменем властивості в обгортці, що містить посилання на оригінал x, після присвоєння обгортки змінній x.
Qwertronix

32

Ось що "is ".

Замість тестування "if a == b ", яке тестує на одне і те ж значення,

тест " if a is b", який перевірятиме той самий ідентифікатор.


20
Чи правильно було б сказати, що Python "є" схоже на Java "==", а Python "==" схоже на Java "equals ()"?
MatrixFrog

2

Як згадує ilya n, id (x) створює унікальний ідентифікатор об'єкта.

Але ваше запитання заплутане, оскільки метод hashCode Java не дає унікального ідентифікатора. HashCode Java працює як більшість хеш-функцій: він завжди повертає одне і те ж значення для одного і того ж об’єкта, два рівні об’єкти завжди отримують рівні коди, а нерівні хеш-значення означають нерівні хеш-коди. Зокрема, два різні та нерівні об'єкти можуть отримати однакове значення.

Це бентежить, оскільки криптографічні хеш-функції значно відрізняються від цих, і більше нагадують (хоча і не зовсім) "унікальний ідентифікатор", який ви просили.

Еквівалент Python методу Java hashCode - hash (x).


Ось чому я чітко згадав метод хеш-коду java.lang.Object. Що за замовчуванням створює унікальний термін для цього об’єкта. Я усвідомлюю, що інші реалізації хеш-коду можуть різнитися і можуть відрізнятися.
сам

Але в цьому суть: hashCode не видає унікального довгого. Він створює longs, які намагаються не зіткнутися, але ви не можете зіставити рядки з longs і створити унікальне значення.
Нед Батчелдер,

1
... і стару нитку, яку я знаю. Але я хотів зазначити, що id () унікальний лише тоді, коли обидва об'єкти все ще існують. Після звільнення ідентифікатор може бути присвоєний іншому об'єкту за "Два об'єкти, що не перекриваються, можуть мати однакове значення id ()." посилання
Роберт Лугг

Але в Python hash(.)не працює для списків ... Я знаю, що список можна змінювати, але мені просто потрібно створити число на основі вмісту списку. Можливо сума (myList), як погана хеш-функція ...
flow2k

-1

Не потрібно порівнювати об’єкти, перш ніж поміщати їх у набір. про це вже дбає семантика set ().

   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>])

Примітка: Вам дійсно не потрібно перевизначати хеш, щоб довести таку поведінку :-)


2
Ваше рішення залежить від типу класу, який успадковується: class B(str): passякщо його викликати за допомогою set([B(), B()])lead to set(['']). Ідентифікація зі словників, як правило, неявно залежить від id(x)об’єктів, вам слід просто використовувати її явно та уникати кутових випадків.
Арне

@ArneRecknagel ти маєш рацію. але що б ви поклали в набір після перевірки id (x)?
user942640
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.