2013-02-11 34 views
9

Vâng, câu hỏi nằm trong tiêu đề: làm cách nào để xác định từ điển python với khóa không thay đổi nhưng giá trị có thể thay đổi? Tôi đã đưa ra điều này (trong python 2.x):Xác định từ điển python với các khóa không thay đổi nhưng giá trị có thể thay đổi

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) 

nhưng có vẻ với tôi (không ngạc nhiên) thay vì cẩu thả. Đặc biệt, điều này là an toàn hay có nguy cơ thực sự thay đổi/thêm một số khóa, vì tôi đang kế thừa từ dict? Cảm ơn.

+0

Vâng, có thể ai đó có thể gọi 'dict .__ setitem __() 'trên một thể hiện của' FixedDict', không? – cdhowie

+2

Bạn nên kiểm tra để chắc chắn rằng 'dict.update' gọi' __setitem__' - Mặc dù, ngay cả khi có, tôi không chắc liệu có phụ thuộc vào việc thực thi hay không ... – mgilson

+0

('update' bỏ qua' __setitem__') – katrielalex

Trả lời

10

Xem xét proxy dict thay vì phân lớp nó. Điều đó có nghĩa rằng chỉ có các phương thức mà bạn xác định sẽ được cho phép, thay vì rơi trở lại các triển khai của 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] 

Ngoài ra, bạn nên sử dụng chuỗi định dạng thay vì + để tạo ra các thông báo lỗi, vì nếu không nó sẽ bị lỗi đối với bất kỳ giá trị mà không phải là một chuỗi.

1

Cách ngăn người nào đó thêm khóa mới phụ thuộc hoàn toàn vào lý do ai đó có thể thử thêm khóa mới. Theo trạng thái nhận xét, hầu hết các phương pháp từ điển sửa đổi các phím không đi qua __setitem__, do đó, cuộc gọi .update() sẽ thêm các phím mới tốt.

Nếu bạn chỉ mong đợi ai đó sử dụng d[new_key] = v thì __setitem__ của bạn là tốt. Nếu họ có thể sử dụng các cách khác để thêm khóa, thì bạn phải đặt nhiều công việc hơn. Và tất nhiên, họ luôn có thể sử dụng quyền này để làm điều đó:

dict.__setitem__(d, new_key, v) 

Bạn không thể làm mọi thứ thật bất biến trong Python, bạn chỉ có thể dừng những thay đổi cụ thể.

11

Vấn đề với kế thừa trực tiếp từ dict là rất khó tuân thủ hợp đồng đầy đủ của dict (ví dụ: trong trường hợp của bạn, phương thức update sẽ không hoạt động theo cách nhất quán).

gì bạn muốn, là để mở rộng collections.MutableMapping:

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 

Lưu ý rằng bản gốc (bọc) dict sẽ được sửa đổi, nếu bạn không muốn điều đó xảy ra, sử dụng copy or deepcopy.

+0

+1 'MutableMapping' là cách để đi đến đây – katrielalex

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