2011-02-15 15 views
6

Próbuję zgłosić błąd, jeśli użytkownik wprowadzi zduplikowany klucz w słowniku. Słownik znajduje się w pliku i użytkownik może edytować plik ręcznie.Podnoszenie błędów w przypadku duplikowania kluczy w słowniku

Przykład:

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

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

nowy klucz 'a' już istnieje ...

Jak mogę przetestować Dico i ostrzega użytkownika, gdy załadować Dico z pliku?

+0

Jak ładujesz słownik z pliku? –

+1

@HughBothwell: z 'from x import dico' – Thammas

Odpowiedz

12

Napisz podklasę dyktowania, nadpisaj __setitem__ tak, że zgłasza błąd podczas wymiany istniejącego klucza; przerobić plik, aby używał konstruktora nowej podklasy zamiast domyślnych wbudowanych dict.

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) 

wtedy plik będzie musiał być zapisany jako

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') 
     ), 

     .... 
    ) 
) 

wykorzystaniem krotki zamiast dicts dla importu pliku (napisany przy użyciu {} notacji, byłoby użyć konstruktora domyślnego dict, a duplikaty znikną, zanim konstruktor Dicta je otrzyma!).

+0

To jest najlepsze rozwiązanie! Podnosi oczekiwany wyjątek nie tylko przy próbie dodawania elementów jeden po drugim, ale także po przekonwertowaniu listy krotek z powtarzającymi się pierwszymi elementami do słownika: Dict ([(1, 2), (3, 4), (1, 6)]). – jciloa

1

Domyślne zachowanie Pythona polega na dyskretnym zastępowaniu duplikatów podczas deklarowania słownika.

Możesz utworzyć własną klasę słownika, która sprawdzi, czy element był już w słowniku przed dodaniem nowych elementów, a następnie skorzystaj z tego. Ale wtedy musiałbyś zmienić swoją deklarację dico w tym pliku na coś, co pozwala na duplikaty, jak na przykład lista krotek.

Następnie, po załadowaniu tego pliku danych, przeanalizowałbyś go w specjalnym "podklasowanym" dict.

4

Będziesz potrzebował niestandardowego dicta, który może odrzucić z ValueError, jeśli klucz jest już obecny.

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) 

Oto jak to działa.

>>> 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 
+1

Zauważ, że k w self.keys() to O (n), powinieneś prawdopodobnie używać 'in self' bezpośrednio (nie sprawdzał) – iggy

+0

Nie podnosi to oczekiwanego wyjątku, gdy konwertujesz listę krotek z powtarzającymi się pierwszymi elementami do słownika: RejectingDict ([(1, 2), (3, 4), (1, 6)]). Przyjęte rozwiązanie (Hugh Bothwell) również działa w tej sprawie. – jciloa

+0

oh, używanie self.keys() jest zbyt wolne – spiritwolfform

3

wspak
WRÓĆ

from x import dico nie jest to bardzo dobry pomysł - jesteś pozwalając użytkownikom edytować kod, który następnie wykonać ślepo. Ryzykujesz proste literówki powodujące błąd składni, aż do złośliwych rzeczy, takich jak import os; os.system("rm whatever"); dico = {}.

Nie przejmuj się z podklasy dict. Napisz własny program ładujący dykt-of-dicts. To nie takie trudne ... przeczytaj plik danych, sprawdź przed każdym wstawieniem, czy klucz już istnieje; jeśli tak, zaloguj się komunikat o błędzie zawierający istotne informacje, takie jak numer linii i duplikat klucza oraz jego wartość. Na koniec, jeśli wystąpiły jakiekolwiek błędy, podnieś wyjątek. Może się okazać, że istnieje już moduł do tego wszystkiego ... dostarczony w Pythonie ConfigParser, czyli konfigurator plików konfiguracyjnych, nie jest tym, czego potrzebujesz.

Nawiasem mówiąc, nie ma jednego "root" klucz na najwyższym poziomie raczej bezcelowe?

+0

Dzięki za komentarz. 'dico' jest w rzeczywistości plikiem ustawień. Jako że jestem początkującym pytonem i nie rozumiem wszystkich kodów z odpowiedzi, myślę, że zamiast tego użyję programu ConfigParser ... – Thammas

+0

@Thammas: Huh? (1) "" "dico jest w rzeczywistości plikiem ustawień" "": Zgodnie z twoim pytaniem 'dico' to nazwa 3-poziomowego słownika kodu źródłowego [masz nadzieję !!] w pliku o nazwie' x.py' (2) Co sprawia wrażenie, że program ConfigParser obsługuje zduplikowane wykrywanie dzięki znaczącym komunikatom o błędach? –

+0

Masz rację, dico jest słownikiem w file.py ... Miałem wypowiedzenia ... Masz rację także o ConfigParser! Spróbuję przestudiować kody podane w odpowiedziach. – Thammas

1

Jeśli chcesz się upewnić, że błąd jest podniesiona podczas dict konstrukcji z duplikatów kluczy, tylko wzmocnią natywną sprawdzanie argumentów słów kluczowych Pythona:

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

chyba że jestem brakuje czegoś, nie ma potrzeby do podklasy dict .

Powiązane problemy