У меня есть два перечисления NAME
и ALIAS
, которые гарантированно содержат одинаковое количество констант, и мне нужен способ преобразования каждой константы из NAME
в соответствующую ей из ALIAS
и наоборот. Например:
def name_to_alias(name):
if name == Name.PAUL:
return Alias.STARCHILD
elif name == Name.GENE:
return Alias.DEMON
...
def alias_to_name(alias):
if alias == Alias.STARCHILD:
return Name.PAUL
elif alias == Alias.DEMON:
return Name.GENE
...
Я не хочу поддерживать две подобные функции (или диктовки). В идеале я хотел бы иметь сопоставления перечислений в одной структуре данных, к которой я мог бы получить доступ из обеих функций преобразования.
Я думаю о чем-то вроде:
mappings = {
Name.PAUL: Alias.STARCHILD
Name.GENE: Alias.DEMON
...
}
Это будет работать для преобразования из Name
в Alias
, но в обратном случае могут возникнуть проблемы (что произойдет, если я сделаю ошибку копирования и вставки и в итоге получу два dict-ключа с одинаковым значением?). Есть ли простой и безопасный способ добиться этого?
Похоже, вам следует избавиться от перечислений
@MarkRansom «Дикты так не работают», конечно, работают; d = {"a": 1, "b": 1}
— это совершенно правильный Python. В этом случае было бы ошибкой иметь такие повторяющиеся значения, поэтому я сказал «случайно».
@klutt, к сожалению, это не так просто, поскольку они глубоко встроены в две разные части системы, которые я пытаюсь заставить общаться друг с другом.
@Martin Это удивительно, учитывая, что вы только что гарантировали, что два типа перечислений имеют одинаковое количество членов - как вы скомпилировали Alias
с конфликтующими именами членов? Возможно, отображение не так симметрично, как вы изначально предполагали?
@MathiasR.Jessen Я имел в виду, что могу допустить ошибку копирования и вставки при добавлении новых записей в словарь. Перечисление, имеющее одинаковое количество членов, не имеет к этому никакого отношения. Я отредактировал вопрос, чтобы прояснить это.
Ваш редактор (или, в конечном итоге, среда выполнения Python, выполняющая ваш код) сообщит вам, что произошло столкновение, и вы сможете вернуться и исправить свою ошибку. Боюсь, я не понимаю, какое отношение небрежное копирование имеет к вашему вопросу о сопоставлении значений перечисления. Можете ли вы рассказать нам больше об отношениях между Name
и Alias
? Это 1 к 1 или многие к 1?
Я предполагаю, что ваша функция get_name из псевдонима должна возвращать все совпадающие имена, например def alias_to_name(alias): return [name for name, a in mappings.items() if a == alias]
@PepeNO, вот в чем проблема: в идеальном мире таких значений не было бы больше одного. Думаю, в этом случае я мог бы просто добавить проверку и ошибку, но я надеялся на более «элегантное» решение.
@MathiasR.Jessen, счет 1:1. Я не понимаю, как среда выполнения автоматически обнаружит эту проблему; как я уже сказал, d = {"a": 1, "b": 1}
— это совершенно правильный Python. Если бы я сделал то, что рекомендовал @PepeNO, мне все равно пришлось бы добавить ручную проверку, чтобы убедиться, что найдено только одно значение.
@Мартин, я думал, ты говоришь о создании обратного словаря, который позволит искать ключи на основе их значений.
@MatBailie да, это может сработать.
Учитывая, что в сопоставлениях более одного имени может иметь один и тот же псевдоним, безопасная функция должна вызывать ошибку, например
mappings = {
Name.PAUL: Alias.STARCHILD,
Name.GENE: Alias.DEMON,
Name.PETER: Alias.CATMAN,
Name.ALICE: Alias.DEMON
}
def alias_to_name(alias):
#check if the alias is more than once in the mappings and raise an error
if list(mappings.values()).count(alias) > 1:
raise ValueError('Alias is not unique', alias, [name for name, a in mappings.items() if a == alias])
else:
return [name for name, a in mappings.items() if a == alias]
Это выведет
('Alias is not unique', <Alias.DEMON: 2>, [<Name.GENE: 2>, <Name.ALICE: 4>])
Да, именно об этом я и думал. Но я ожидал, что будет существовать более «элегантное» решение, например. полностью использовать другую структуру данных и т. д.
Это линейный поиск. Это может быть хорошо для коротких списков, но очень дорого для больших. Мало того, проверка нескольких псевдонимов удваивает объем необходимой работы.
«Что произойдет, если у меня случайно окажется два ключа dict с одинаковым значением?» Не делайте этого, дикты так не работают. При необходимости вы можете создать список значений с одним ключом, но как бы вы выбрали один из разных вариантов?