2012-02-17 21 views
5

Như nhiều câu hỏi về chủ đề ở đây trên SO chứng thực, tham gia một lát một cuốn từ điển là một nhiệm vụ khá phổ biến, với một giải pháp khá tốt đẹp:Python tạo view dict riêng của tập hợp con của từ điển

{k:v for k,v in dict.viewitems() if some_test(k,v)} 

Nhưng tạo ra một từ điển mới, với ánh xạ riêng của nó. Đối với nhiều hoạt động, sẽ thật tuyệt khi chỉ có một cái nhìn bất biến về nguyên tắc gốc (tức là nó không hỗ trợ các hoạt động gán hoặc xóa trên màn hình). Việc thực hiện một kiểu như vậy có lẽ là dễ dàng, nhưng nó không tốt để có sự gia tăng của các lớp tiện ích cục bộ.

Vì vậy, câu hỏi của tôi là: có cách tích hợp để có được "chế độ xem tập hợp con" như vậy không? Hoặc là có một thư viện của bên thứ ba (tốt nhất là có sẵn thông qua PyPi) cung cấp một thực hiện tốt các tiện ích như vậy?

+1

Tôi cho rằng "chế độ xem bất biến" trên từ điển chính xác là những gì bạn nhận được với mã ví dụ của mình ... vì không có bản sao từ điển riêng biệt, tôi không chắc chắn bạn sẽ làm như thế nào "không thể thay đổi" một phần công việc. – larsks

+0

@larsks: Đơn giản là không hỗ trợ chuyển nhượng. – Marcin

+1

@ larsks: Tôi giả định rằng "xem bất biến" OP có nghĩa là chính đối tượng xem không có phương pháp để biến đổi từ điển (ví dụ pop) và bất kỳ thay đổi nào đối với dict được bao bọc sẽ hiển thị ngay lập tức trong chế độ xem. Tất nhiên, nó không phải là bất biến theo nghĩa "sâu" - tức là, nếu bạn làm my_view [some_key] .append (12), thì tất nhiên giá trị tương ứng với 12 sẽ được sửa đổi. –

Trả lời

4

này là khá dễ dàng để thực hiện:

from collections import Mapping 
class FilteredItems(Mapping): 
    def __init__(self, source, filter): 
     self.source = source 
     self.p = filter 

    def __getitem__(self, key): 
     x = self.source[key] 
     if self.p(key,x): 
      return key,x 
     else: 
      raise KeyError(key) 


d2 = FilteredItems(d, some_test) 
+0

+1 để sử dụng lớp cơ sở Bản đồ – theheadofabroom

+2

Có, điều này là khá dễ thực hiện, và điều này có vẻ tốt, nhưng như đã nói, rất nhiều triển khai và tên địa phương không phải là một điều tuyệt vời. – Marcin

2

Để làm rõ ngữ nghĩa, bạn đang nghĩ đến một cái gì đó như thế này :?

class FilteredDictView: 
    def __init__(self, base_dict, test): 
     self._base_dict = base_dict 
     self._test = test 
    def __getitem__(self, key): 
     value = self._base_dict[key] # might throw KeyError 
     if not self._test(key,value): 
      throw KeyError(key) 
     return value 
    # ... implement remaining dict-like-methods ... 

Nếu vậy, tôi không biết bất kỳ lớp thứ ba nào như vậy. Nếu bạn muốn thực hiện các phương thức còn lại dễ dàng hơn một chút, bạn có thể xem sử dụng "UserDict" như một lớp cơ sở, về cơ bản chỉ là một trình bao bọc cho dict (thuộc tính "UserDict.data" được sử dụng để lưu trữ dict được bao bọc) .

+0

Vâng, chính xác loại điều đó. – Marcin

4

Dường như không có cách tích hợp để có chế độ xem thành từ điển. Cách giải quyết đơn giản nhất dường như là cách tiếp cận của Jochen. Tôi thích mã của mình một chút để làm cho nó làm việc cho mục đích của tôi:

from collections import MutableMapping 

class DictView(MutableMapping): 
    def __init__(self, source, valid_keys): 
     self.source, self.valid_keys = source, valid_keys 

    def __getitem__(self, key): 
     if key in self.valid_keys: 
      return self.source[key] 
     else: 
      raise KeyError(key) 

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

    def __iter__(self): 
     for key in self.valid_keys: 
      yield key 

    def __setitem__(self, key, value): 
     if key in self.valid_keys: 
      self.source[key] = value 
     else: 
      raise KeyError(key) 

    def __delitem__(self, key): 
     self.valid_keys.remove(key) 

d = dict(a=1, b=2, c=3) 
valid_keys = ['a', 'c'] 
d2 = DictView(d, valid_keys) 
d2['a'] = -1 # overwrite element 'a' in source dictionary 
print d # prints {'a': -1, 'c': 3, 'b': 2} 

Vì vậy d2 cư xử giống như một cuốn từ điển về mọi mặt trừ in, do phương pháp khác nhau __repr__(). Kế thừa từ dict để nhận __repr__() sẽ yêu cầu thực hiện lại từng phương pháp, như được thực hiện cho collections.OrderedDict. Nếu chỉ muốn một chế độ chỉ đọc, người ta có thể kế thừa từ collections.Mapping và lưu triển khai __setitem__()__delitem__(). Tôi tìm thấy DictView hữu ích để chọn thông số từ self.__dict__ và truyền chúng ở dạng gọn nhẹ.

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