2013-09-26 28 views
15

Tôi có một lớp học như:Làm thế nào để làm cho từ điển chỉ đọc bằng Python

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

và tại một số thời điểm tôi muốn cấm self.data lĩnh vực sửa đổi.

Tôi đã đọc trong PEP-416 rejection notice rằng có rất nhiều cách để thực hiện. Vì vậy, tôi muốn tìm thấy những gì họ đang có.

Tôi cố gắng này:

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

Điều đó sẽ làm việc nhưng trước tiên, python3.3 của nó + và thứ hai, khi tôi làm điều này "cấm" nhiều lần tôi có được điều này:

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

dù sẽ tốt hơn nếu chỉ nhận được mappingproxy({}) vì tôi sẽ "cấm" nhiều lần. Kiểm tra isinstance(MappingProxyType) là một tùy chọn, nhưng tôi nghĩ rằng các tùy chọn khác có thể tồn tại.

Cảm ơn

+1

http://stackoverflow.com/questions/8752451/how-to-change-the-behavior -of-a-python-dictionarys-setattr có thể giúp bạn – Garfield

+3

Việc triển khai frozendict trông khá tầm thường: https://github.com/slezica/python-frozendict/blob/master/frozendict/__init__.py – georg

+2

@codelover Đúng vậy, Tôi có thể ghi đè '__setitem__' bằng' throw NotImplemented'. Có đảm bảo rằng sẽ không có cách nào để sửa đổi các khóa hoặc giá trị thông qua bất kỳ thuộc tính 'dict' chuẩn nào trong bất kỳ triển khai python nào không? – sshilovsky

Trả lời

23

Sử dụng collections.Mapping ví dụ:

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

Nó có thể được rằng điều này chỉ làm cho các dict chính nó, nhưng không necessarilty chứa dicts bất biến? Tôi hiện đang muốn thực hiện một dict lồng nhau đại diện cho một cấu hình immuatable. –

5

Rất dễ, bạn chỉ cần ghi đè phương pháp mặc định của dict!
Dưới đây là một ví dụ:

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, bạn cũng có thể loại bỏ .pop, .update và các phương pháp khác mà bạn cần. Chỉ chơi đùa với nó thôi.

+0

Làm thế nào để bạn áp dụng điều này "vào một lúc nào đó"? Tôi đoán OP cần dict được đọc-ghi, sau đó làm cho nó đông lạnh sau một thời gian. – justhalf

+0

@justhalf, hãy xem mã đã sửa đổi của tôi – JadedTuna

+1

còn 'clear',' update', 'pop',' setdefault' là gì? – shx2

15

Đây là thực hiện đầy đủ read-only 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

Để cho phép sao chép chúng bằng cách sử dụng 'copy.copy' và' copy.deepcopy' bạn có thể thêm hai dòng sau: '__copy__ = dict.copy' và' __deepcopy__ = copy._deepcopy_dispatch.get (dict) '. Không được thử nghiệm nhiều. – blueyed

+0

Chỉ cần gọi '.copy()' trên nó cũng hoạt động trực tiếp. – blueyed

Các vấn đề liên quan