2013-09-26 12 views
15

Ho una classe come:Come rendere dizionario di sola lettura in Python

class A: 
    def __init__(self): 
     self.data = {} 

e ad un certo momento voglio vietare la modifica self.data campi.

Ho letto in PEP-416 rejection notice che ci sono molti modi per farlo. Quindi mi piacerebbe trovare quello che sono.

ho provato questo:

a = A() 
a.data = types.MappingProxyType(a.data) 

che dovrebbe funzionare ma in primo luogo, la sua python3.3 + e in secondo luogo, quando faccio questo "divieto" più volte ho ottenere questo:

>>> a.data = types.MappingProxyType(a.data) 
>>> a.data = types.MappingProxyType(a.data) 
>>> a.data 
mappingproxy(mappingproxy({})) 

però sarebbe molto meglio ottenere solo mappingproxy({}) perché sto andando a "vietare" un sacco di volte. Il controllo di isinstance(MappingProxyType) è un'opzione, ma penso che possano esistere altre opzioni.

Grazie

+1

http://stackoverflow.com/questions/8752451/how-to-change-the-behavior -of-a-python-dictionarys-setattr può aiutarti – Garfield

+3

Un'implementazione frozendict sembra piuttosto banale: https://github.com/slezica/python-frozendict/blob/master/frozendict/__init__.py – georg

+2

@codelover Proprio così, Posso eseguire l'override di '__setitem__' con' throw NotImplemented'. È garantito che non ci sarà modo di modificare chiavi o valori tramite qualsiasi attributo 'dict' standard in qualsiasi implementazione Python? – sshilovsky

risposta

23

Utilizzare collections.Mapping ad es.

import collections 

class DictWrapper(collections.Mapping): 

    def __init__(self, data): 
     self._data = data 

    def __getitem__(self, key): 
     return self._data[key] 

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

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

HTH,

+0

Può essere che questo faccia solo il ditt vero, ma non necessariamente le diciture immutabili? Attualmente voglio fare un dict annidato che rappresenta un config immutabile. –

5

molto facile, basta sostituire i metodi di dict di default!
Ecco un esempio:

class ReadOnlyDict(dict): 

    __readonly = False 

    def readonly(self, allow=1): 
     """Allow or deny modifying dictionary""" 
     self.__readonly = bool(allow) 

    def __setitem__(self, key, value): 

     if self.__readonly: 
      raise TypeError, "__setitem__ is not supported" 
     return dict.__setitem__(self, key, value) 

    def __delitem__(self, key): 

     if self.__readonly: 
      raise TypeError, "__delitem__ is not supported" 
     return dict.__delitem__(self, key) 

BTW, è possibile anche rimuovere .pop, .update e altri metodi necessari. Basta giocarci.

+0

Come si applica questo "ad un certo momento"? Immagino che OP abbia bisogno che il dettato sia di lettura-scrittura, quindi lo faccia congelare dopo un po 'di tempo. – justhalf

+0

@justhalf, controlla il mio codice modificato – JadedTuna

+1

cosa dire 'clear',' update', 'pop',' setdefault'? – shx2

15

Questa è la piena attuazione di sola lettura dict:

class ReadOnlyDict(dict): 
    def __readonly__(self, *args, **kwargs): 
     raise RuntimeError("Cannot modify ReadOnlyDict") 
    __setitem__ = __readonly__ 
    __delitem__ = __readonly__ 
    pop = __readonly__ 
    popitem = __readonly__ 
    clear = __readonly__ 
    update = __readonly__ 
    setdefault = __readonly__ 
    del __readonly__ 
+0

per consentire la copia eseguita '' copy.copy' e copy.deepcopy' si potrebbe desiderare di aggiungere le seguenti due righe: '__copy__ = dict.copy' e' __deepcopy__ = copy._deepcopy_dispatch.get (dict) '. Non molto testato però. – blueyed

+0

Anche la semplice chiamata '.copy()' funziona direttamente. – blueyed

Problemi correlati