Как изменить представление класса, если класс является ключом словаря?

#python

Вопрос:

Рассмотрим следующий код:

 class DummyClass:
    
    def __init__(self, name):
        self.name = name

obj_1 = DummyClass("name_1")
obj_2 = DummyClass("name_2")

my_dict = {
    obj_1: "value_1",
    obj_2: "value_2"
}

print(my_dict)
 

Выход

 {<__main__.DummyClass object at 0x7f8f6493a0b8>: 'value_1', <__main__.DummyClass object at 0x7f8f649869e8>: 'value_2'}
 

Этот код создал словарь my_dict , содержащий экземпляры ключей DummyClass as.

Я хотел бы знать, есть ли волшебная функция (например __something__ ), которую я могу переопределить, DummyClass чтобы приведенный выше код выдавал следующий результат:

 {'name_1': 'value_1', 'name_2': 'value_2'}
 

где name_1 и name_2 являются обеими строками, name свойствами DummyClass экземпляров.

Я не хочу менять визуализацию или печать, я хочу на самом деле изменить ключ в памяти.

Комментарии:

1. Не знаю, почему кто-то понизил голос. Если бы я не знал названия функции, которую искал, я не смог бы найти ответ.

2. Я, вероятно, упускаю здесь главное, но мне кажется, что это my_dict = {obj_1.name: "value_1", obj_2.name: "value_2" } сделает то, что вы хотите.

3. В данном конкретном случае-да. Но есть ли модель общего способа, которая позволила бы мне писать my_dict = {obj_1: "value_1", obj_2: "value_2" } и получать те же результаты, my_dict = {obj_1.name: "value_1", obj_2.name: "value_2" } что и ? Похоже, мне нужно переопределить __repr__ .

4. Мне кажется, вы ищете то, что Delphi называет атрибутом по умолчанию : это значение RH имени экземпляра голого класса, которое вы, конечно, должны объявить, иначе что дает self.name приоритет над другими атрибутами? Но в Python нет известного мне механизма, позволяющего сделать один атрибут более важным, чем другие. Я думаю, было бы лучше объяснить, почему вы считаете, что вам нужен такой механизм.

5. Тогда нет, это невозможно сделать. Сам объект является ключом, нет никакого волшебного метода для «фактического значения, которое будет использоваться в качестве ключа, когда оно используется в качестве ключа словаря» . Как было предложено выше, вы должны указать контекст, проблему, которую это решит.

Ответ №1:

__repr__ Метод используется для генерации строки, которая dict используется для отображения ключей. Не существует механизма для изменения ключа во dict время создания или обновления, а dict также конкретного способа изменения способа отображения ключа.

По умолчанию DummyClass наследует свой __repr__ метод от object , который и создает <...> строку. Переопределение __repr__ для возврата строки, построенной из name атрибута.

 class DummyClass:

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return f"'{self.name}'"
 

Было предложение создать словарь, преобразующий ключи, но оно было отклонено. Это позволило бы вам написать что-то вроде

 d = TransformDict(lambda x: x.name)
d[obj_1] = ...
d[obj_2] = ...
 

и результат dict будет вести себя так, как если 'name1' бы и 'name2' были ключами (при этом все еще позволяя доступ к исходным ключам obj_1 и obj_2 при необходимости).

Комментарии:

1. Это приведет к правильному печатному представлению, но, как указано в комментариях к вопросу, это не делает фактический ключ словаря строкой; он просто делает его похожим на строку ниже print .

2. Я недостаточно четко сформулировал это. Либо экземпляр dict является ключом, либо это не так. dict не предоставляет способа изменить ключ во время создания dict (хотя см. Отклоненный PEP-455 , в котором предлагался именно такой механизм) и не предоставляет dict конкретного крючка для отображения ключа.

3. Да, я вовсе не критикую твой ответ. Я просто не хочу, чтобы ОП думал, что это полное решение их проблемы, учитывая, что они прояснили данный вопрос в комментариях. Как написано, это ответ на поставленный вопрос. В комментариях просто есть дополнительный контекст, который я не хочу упускать.

4. Я попытался прояснить ответ таким образом, чтобы он соответствовал первоначальному намерению.

5. Спасибо. Итак, в заключение, сделает ли использование __repr__ клавиш строками, если __repr__ функция вернет строку?