Как вызвать ошибку, если дублирует ключи в словаре - PullRequest
10 голосов
/ 15 февраля 2011

Я пытаюсь вызвать ошибку, если пользователь вводит дубликат ключа в словаре.Словарь находится в файле, и пользователь может редактировать файл вручную.

Пример:

dico= {'root':{
                'a':{'some_key':'value',...},
                'b':{'some_key':'value',...},
                'c':{'some_key':'value',...},
                ...

                'a':{'some_key':'value',...},
              }
      }

новый ключ 'a' уже существует ...

Какя могу проверить Dico и предупредить пользователя, когда я загружаю Dico из файла?

Ответы [ 5 ]

15 голосов
/ 15 февраля 2011

Записать подкласс dict, переопределить __setitem__ так, чтобы он выдавал ошибку при замене существующего ключа; перепишите файл, чтобы использовать конструктор вашего нового подкласса вместо встроенных модулей по умолчанию.

import collections

class Dict(dict):
    def __init__(self, inp=None):
        if isinstance(inp,dict):
            super(Dict,self).__init__(inp)
        else:
            super(Dict,self).__init__()
            if isinstance(inp, (collections.Mapping, collections.Iterable)): 
                si = self.__setitem__
                for k,v in inp:
                    si(k,v)

    def __setitem__(self, k, v):
        try:
            self.__getitem__(k)
            raise ValueError("duplicate key '{0}' found".format(k))
        except KeyError:
            super(Dict,self).__setitem__(k,v)

тогда ваш файл должен быть записан как

dico = Dict(
    ('root', Dict(
        ('a', Dict(
            ('some_key', 'value'),
            ('another_key', 'another_value')
        ),
        ('b', Dict(
            ('some_key', 'value')
        ),
        ('c', Dict(
            ('some_key', 'value'),
            ('another_key', 'another_value')
        ),

        ....
    )
)

использование кортежей вместо dicts для импорта файла (при записи с использованием нотации {} будет использоваться конструктор dict по умолчанию, а дубликаты исчезнут до того, как конструктор Dict их получит!).

4 голосов
/ 15 февраля 2011

Вам понадобится пользовательский dict, который можно отклонить с помощью ValueError, если ключ уже присутствует.

class RejectingDict(dict):
    def __setitem__(self, k, v):
        if k in self.keys():
            raise ValueError("Key is already present")
        else:
            return super(RejectingDict, self).__setitem__(k, v)

Вот как это работает.

>>> obj = RejectingDict()
>>> obj[1] = True
>>> obj[2] = False
>>> obj
{1: True, 2: False}
>>> obj[1] = False
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "rejectingdict.py", line 4, in __setitem__
    raise ValueError("Key is already present")
ValueError: Key is already present
2 голосов
/ 15 февраля 2011

НЕПРАВИЛЬНЫЙ ПУТЬ
ВЕРНУТЬСЯ

from x import dico не очень хорошая идея - вы позволяете ПОЛЬЗОВАТЕЛЯМ редактировать код, который затем выполняете вслепую . Вы рискуете простыми опечатками, вызывающими синтаксическую ошибку, вплоть до вредоносных вещей, таких как import os; os.system("rm whatever"); dico = {}.

Не обращайте внимания на подклассы dict. Напишите свой собственный загрузчик dict-of-dicts. Это не так сложно ... читать файл данных, проверять перед каждой вставкой, существует ли ключ; если это так, зарегистрируйте сообщение об ошибке с такими значимыми вещами, как номер строки, дубликат ключа и его значение. В конце, если были какие-либо ошибки, выведите исключение. Вы можете обнаружить, что существует существующий модуль, который делает все это ... предоставленный Python ConfigParser, иначе configparser, кажется, не то, что вам нужно.

Кстати, не имеет ли один «корневой» ключ на верхнем уровне довольно бессмысленно?

1 голос
/ 07 марта 2014

Если вы хотите, чтобы при создании dict возникала ошибка с дублирующимися ключами, просто используйте проверку аргументов собственного ключевого слова Python:

> dict(a={}, a={})
SyntaxError: keyword argument repeated

Если я что-то упускаю, нет необходимости в подклассе dict.

1 голос
/ 15 февраля 2011

По умолчанию Python перезаписывает дубликаты без уведомления при объявлении словаря.

Вы можете создать свой собственный класс словаря, который будет проверять, был ли элемент уже в словаре, прежде чем добавлять новые элементы, а затем использовать это. Но тогда вам придется изменить объявление dico в этом файле на что-то, что позволяет дублировать, например, список кортежей.

Затем, загружая этот файл данных, вы анализируете его в свой специальный «подкласс».

...