2011-02-15 3 views
6

사용자가 사전에 중복 키를 입력하면 오류가 발생합니다. 사전은 파일에 있으며 사용자는 파일을 수동으로 편집 할 수 있습니다.사전에 키를 중복하는 경우 오류를 발생시키는 방법

예 :

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

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

새 키 '는이'이미 존재하는 ...

어떻게 DICO을 테스트하고 난 파일에서 DICO을로드 할 때 사용자에게 경고 할 수 있습니까?

+0

파일에서 사전을로드하는 방법은 무엇입니까? –

+1

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

답변

12

dict의 하위 클래스를 작성하고 __setitem__을 재정 의하여 기존 키를 바꿀 때 오류가 발생합니다. 기본 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) 

다음 파일 대신 {} 표기법을 사용하여 작성된 파일 가져 오기에 대한 dicts (의 튜플을 사용

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

     .... 
    ) 
) 

로 작성되어야 할 것이다, 그것은 기본 DICT 생성자를 사용하고 것 Dict 생성자가 가져 오기 전에 복제본이 사라집니다.).

+0

이것은 최고의 해결책입니다! 항목을 하나씩 추가 할 때뿐만 아니라 첫 번째 항목이 반복 된 튜플 목록을 사전으로 변환 할 때도 예외가 발생합니다. Dict ([(1,2), (3, 4), (1, 6)]). – jciloa

1

파이썬의 기본 동작은 사전을 선언 할 때 자동으로 중복 된 내용을 덮어 쓰는 것입니다.

새 요소를 추가하기 전에 항목이 사전에 있는지 여부를 확인한 다음이를 사용하는 고유 한 사전 클래스를 만들 수 있습니다. 그러나 그 파일에있는 dico이라는 선언을 튜플 목록과 같이 중복을 허용하는 것으로 변경해야합니다.

그런 다음 데이터 파일을로드 할 때 특별 '하위 클래스'딕트로 구문 분석합니다.

4

키가 이미있는 경우 ValueError로 거부 할 수있는 사용자 지정 dict가 있어야합니다.

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

self.keys()의 k는 O (n)이므로 직접 self 자체를 사용해야합니다 (확인하지 않았습니다) – iggy

+0

첫 번째 항목이 반복 된 튜플 목록을 변환하면 예상되는 예외가 발생하지 않습니다 사전에 : RejectingDict ([(1, 2), (3, 4), (1, 6)]). 허용 된 솔루션 (Hugh Bothwell)은이 경우에도 사용할 수 있습니다. – jciloa

+0

오, self.keys()를 사용하는 것이 너무 느림 – spiritwolfform

3

잘못된 방법

from x import dico 아주 좋은 생각이 아니다 BACK GO - 당신이 다음 맹목적으로을 실행하는 사용자 편집 코드를시키는있다. import os; os.system("rm whatever"); dico = {}과 같은 악의적 인 내용에 대해 구문 오류를 일으키는 간단한 오타가 발생할 위험이 있습니다.

서브 클래스 화를 사용하여 약화시키지 마십시오. dict. 자신의 dict-of-dicts loader를 작성하십시오. 그렇게 어렵지는 않습니다 ... 데이터 파일을 읽고 각 삽입 전에 키가 이미 있는지 확인하십시오. 그렇다면 줄 번호, 중복 키 및 해당 값과 같은 의미있는 내용의 오류 메시지를 기록하십시오. 결국 오류가 발생하면 예외를 발생시킵니다. 모든 것을 수행 할 기존 모듈이 있다는 것을 알 수 있습니다 ... Python이 제공 한 ConfigParser 일명 configparser는 원하는 것 같지 않습니다.

그런데 최상위 레벨에 단일 '루트'키가없는 것은 무의미한가요?

+0

의견을 보내 주셔서 감사합니다. 'dico'는 실제로 설정 파일입니다. 필자는 파이썬 초보자로서 모든 코드를 대답으로 이해할 수 없기 때문에 ConfigParser를 대신 사용할 것입니다. – Thammas

+0

@Thammas : 응? (1) "" "dico는 실제로 설정 파일입니다." ": 귀하의 질문에 따르면,'dico'는'x.py'라는 파일에서 3 단계 소스 코드 사전의 이름입니다! (2) ConfigParser가 의미있는 오류 메시지와 함께 중복 된 검색을 지원한다는 인상을주는 것은 무엇입니까? –

+0

맞습니다, dico는 file.py에있는 사전입니다 ... 나는 misspoken을 가졌습니다 ... ConfigParser에 대해서도 당신이 맞습니다! 나는 응답에 제공된 코드를 연구하려고 노력할 것이다. – Thammas

1

오류, 그냥 파이썬의 기본 키워드 인수 검사를 활용하여 중복 키 dict 건설하는 동안 제기되어 있는지 확인하려면 다음

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

내가 뭔가를 누락하지 않는 한, dict를 서브 클래 싱 할 필요가 없기를 .

관련 문제