2013-02-11 66 views
9

खैर, सवाल शीर्षक में है: मैं अपरिवर्तनीय कुंजी के साथ एक पायथन शब्दकोश को परिभाषित कैसे करूं लेकिन परिवर्तनीय मानों को कैसे परिभाषित करूं?अपरिवर्तनीय कुंजी के साथ एक अजगर शब्दकोश परिभाषित करें लेकिन म्यूटेबल मान

class FixedDict(dict): 
    """ 
    A dictionary with a fixed set of keys 
    """ 

    def __init__(self, dictionary): 
     dict.__init__(self) 
     for key in dictionary.keys(): 
      dict.__setitem__(self, key, dictionary[key]) 

    def __setitem__(self, key, item): 
     if key not in self: 
      raise KeyError("The key '" +key+"' is not defined") 
     dict.__setitem__(self, key, item) 

लेकिन यह मेरे (आश्चर्य) करने के लिए लग रहा है बल्कि लापरवाही: मैं इस के साथ आया था (अजगर 2.x में)। विशेष रूप से, क्या यह सुरक्षित है या वास्तव में कुछ कुंजी बदलने/जोड़ने का जोखिम है, क्योंकि मैं dict से विरासत में हूं? धन्यवाद।

+0

ठीक है, कोई व्यक्ति संभवतः 'फिक्स्ड डिक्ट' के उदाहरण पर 'dict .__ setitem __()' को कॉल कर सकता है, नहीं? – cdhowie

+2

आपको यह सुनिश्चित करने के लिए जांच करनी चाहिए कि 'dict.update' कॉल' __setitem__' - हालांकि, अगर यह भी करता है, तो मुझे यकीन नहीं है कि यह कार्यान्वयन निर्भर है या नहीं ... – mgilson

+0

('अद्यतन' बाईपास '__setitem__') – katrielalex

उत्तर

10

उपclassing के बजाय proxying dict पर विचार करें। इसका मतलब है कि dict के कार्यान्वयन पर वापस आने की बजाय, केवल आपके द्वारा परिभाषित विधियों की अनुमति होगी।

class FixedDict(object): 
     def __init__(self, dictionary): 
      self._dictionary = dictionary 
     def __setitem__(self, key, item): 
       if key not in self._dictionary: 
        raise KeyError("The key {} is not defined.".format(key)) 
       self._dictionary[key] = item 
     def __getitem__(self, key): 
      return self._dictionary[key] 

इसके अलावा, आप, + के बजाय स्ट्रिंग स्वरूपण का उपयोग करना चाहिए त्रुटि संदेश उत्पन्न करने के लिए के बाद से अन्यथा यह है कि एक स्ट्रिंग नहीं है किसी भी मूल्य के लिए दुर्घटना होगा।

1

आप किसी को नई कुंजी जोड़ने से कैसे रोकते हैं, इस पर निर्भर करता है कि कोई नई कुंजी जोड़ने का प्रयास क्यों कर सकता है। टिप्पणियों के अनुसार, कुंजी को संशोधित करने वाली अधिकांश शब्दकोश विधियां __setitem__ से नहीं जाती हैं, इसलिए .update() कॉल नई कुंजी को ठीक से जोड़ देगा।

यदि आप केवल d[new_key] = v का उपयोग करने की अपेक्षा करते हैं, तो आपके __setitem__ ठीक है। यदि वे कुंजी जोड़ने के अन्य तरीकों का उपयोग कर सकते हैं, तो आपको अधिक काम करना होगा। और जाहिर है, वे हमेशा इस वैसे भी यह करने के लिए उपयोग कर सकते हैं:

dict.__setitem__(d, new_key, v) 

आप चीजों को सही मायने में अजगर में अपरिवर्तनीय नहीं कर सकते हैं, आप केवल विशेष परिवर्तन रोक सकता है।

11

dict से सीधे विरासत के साथ समस्या यह है कि यह काफी मुश्किल भरा dict के अनुबंध का पालन करने में (जैसे आपके मामले में, update विधि एक सुसंगत तरह से व्यवहार नहीं किया जाएगा) है। ,

import collections 

class FixedDict(collections.MutableMapping): 
    def __init__(self, data): 
     self.__data = data 

    def __len__(self): 
     return len(self.__data) 

    def __iter__(self): 
     return iter(self.__data) 

    def __setitem__(self, k, v): 
     if k not in self.__data: 
      raise KeyError(k) 

     self.__data[k] = v 

    def __delitem__(self, k): 
     raise NotImplementedError 

    def __getitem__(self, k): 
     return self.__data[k] 

    def __contains__(self, k): 
     return k in self.__data 

ध्यान दें कि मूल (लिपटे) dict संशोधित किया जाएगा यदि आप ऐसा करने के लिए, copy or deepcopy का उपयोग नहीं करते हैं:

तुम क्या चाहते, विस्तार करने के लिए collections.MutableMapping है।

+0

+1 'MutableMapping' यहां जाने का तरीका है – katrielalex