2013-09-26 19 views
15

Mam klasy takich jak:Jak słownika tylko do odczytu w Pythonie

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

iw pewnym momencie chcę zabraniać self.data Pola modyfikacji.

Przeczytałem w PEP-416 rejection notice, że istnieje wiele sposobów, aby to zrobić. Więc chciałbym znaleźć to, czym są.

Próbowałem to:

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

To powinno działać, ale po pierwsze, jego python3.3 + i drugi, kiedy to zrobić "zakaz" wiele razy mam to:

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

chociaż byłoby znacznie lepiej uzyskać tylko mappingproxy({}), ponieważ zamierzam "zakazać" wiele razy. Sprawdzanie isinstance(MappingProxyType) jest opcją, ale myślę, że mogą istnieć inne opcje.

Dzięki

+1

http://stackoverflow.com/questions/8752451/how-to-change-the-behavior -of-a-python-dictionarys-setattr może ci pomóc – Garfield

+3

Implementacja frozendict wygląda dość trywialnie: https://github.com/slezica/python-frozendict/blob/master/frozendict/__init__.py – georg

+2

@codelover To prawda, Mogę przesłonić '__setitem__' z' throw NotImplemented'. Czy istnieje gwarancja, że ​​nie będzie możliwości modyfikacji kluczy lub wartości za pomocą standardowych atrybutów 'dyktowanych 'w jakiejkolwiek implementacji pythona? – sshilovsky

Odpowiedz

23

Użyj collections.Mapping np.

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

Czy to możliwe, że czyni to sam dyktat, ale nie musi zawierać dyktatury niezmienne? Obecnie chcę utworzyć zagnieżdżony dict przedstawiający konfigurację, która może być odtworzona. –

5

Bardzo proste, wystarczy zastąpić domyślne metody dyktowania!
Oto przykład:

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, można również usunąć .pop, .update i inne metody, których potrzebujesz. Po prostu baw się z tym.

+0

Jak zastosować to "w pewnym momencie"? Zgaduję, że OP potrzebuje dyktatu do odczytu i zapisu, a po jakimś czasie go zamrozić. – justhalf

+0

@justhalf, sprawdź mój zmodyfikowany kod – JadedTuna

+1

co z 'clear',' update', 'pop',' setdefault'? – shx2

15

To jest pełna realizacja tylko do odczytu 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

Aby umożliwić ich kopiowanie za pomocą 'copy.copy' i' copy.deepcopy' możesz dodać następujące dwa wiersze: '__copy__ = dict.copy' oraz' __deepcopy__ = copy._deepcopy_dispatch.get (dict) '. Nie sprawdzono jednak zbyt wiele. – blueyed

+0

Samo wywołanie '.copy()' również działa. – blueyed