2016-03-01 18 views
5

Tôi đã viết một mã để tối ưu hóa thiết kế bằng cách sử dụng thư viện Inspyred và việc thực hiện các thuật toán di truyền của nó. Về bản chất, quá trình tối ưu hóa tạo ra một số lượng lớn các biến thể trên một cấu trúc dữ liệu duy nhất, là một từ điển lồng nhau trong trường hợp của tôi.Từ điển Python chỉ lưu trữ các thay đổi

Để giảm lượng bộ nhớ được sử dụng trong quy trình, tôi đã cố tạo một loại loại từ điển khác biệt, chỉ lưu trữ các mục khác với từ điển cơ sở. Lý do cho điều này là trong một trường hợp điển hình, 95% dữ liệu trong cấu trúc dữ liệu sẽ không bị sửa đổi trong bất kỳ biến thể nào, nhưng bất kỳ phần nào của cấu trúc dữ liệu đều có thể chứa các biến thể. Vì vậy, vì lý do linh hoạt, tôi muốn có một kiểu dữ liệu hoạt động nhiều hơn hoặc ít hơn như một từ điển, nhưng chỉ lưu trữ các thay đổi.

Đây là kết quả của nỗ lực của tôi để tạo này:

#!/usr/bin/python 

import unittest 
import copy 

global_base={} 

class DifferentialDict(object): 
    """ 
    dictionary with differential storage of changes 
    all DifferentialDict objects have the same base dictionary 
    """ 

    def __init__(self,base=None): 
     global global_base 

     self.changes={} 

     if not base==None: 
      self.set_base(base) 

    def set_base(self,base): 
     global global_base 
     global_base=copy.deepcopy(base) 

    def __copy__(self): 
     return self 

    def __deepcopy__(self): 
     new=DifferentialDict() 
     new.changes=copy.deepcopy(self.changes) 
     return new 

    def get(self): 
     global global_base 
     outdict=copy.deepcopy(global_base) 
     for key in self.changes: 
      outdict[key]=self.changes[key] 
     return outdict 

    def __setitem__(self,key,value): 
     self.changes[key]=value 

    def __getitem__(self,key): 
     global global_base 
     if key in self.changes: 
      return self.changes[key] 
     else: 
      return global_base[key] 

class TestDifferentialDict(unittest.TestCase): 
    def test1(self): 
     ldict={'a':{1:2,3:4},'b':{'c':[1,2,3],'d':'abc'}} 
     ddict=DifferentialDict(base=ldict) 

     self.assertEqual(ddict['a'],{1:2,3:4}) 
     ddict['a']=5 
     self.assertEqual(ddict['a'],5) 

    def test2(self): 
     ldict={'a':{1:2,3:4},'b':{'c':[1,2,3],'d':'abc'}} 
     ddict1=DifferentialDict(base=ldict) 
     ddict2=DifferentialDict(base=ldict) 

     ddict1['a'][3]=5 
     ddict2['a'][3]=7 
     self.assertEqual(ddict1['a'][3],5) 
     self.assertEqual(ddict2['a'][3],7) 

    def test3(self): 
     ldict={'a':{1:2,3:4},'b':{'c':[1,2,3],'d':'abc'}} 
     ddict1=DifferentialDict(base=ldict) 
     ddict2=ddict1.__deepcopy__() 

     ddict1['a'][3]=5 
     ddict2['a'][3]=7 
     self.assertEqual(ddict1['a'][3],5) 
     self.assertEqual(ddict2['a'][3],7) 



if __name__ == "__main__": 
    unittest.main() 

Nó hoạt động tốt cho một cuốn từ điển đơn giản, nhưng bị phá vỡ khi từ điển mới sẽ được lồng vào trong từ điển chính. Tôi hiểu rằng điều này xảy ra bởi vì các từ điển cấp hai này là từ điển Python thực thay vì instantiations của DifferentialDict của tôi, dẫn đến ghi đè các mục trong global_base thay vì thay đổi trong self.changes. Tuy nhiên, họ phải là do tiền đề rằng tất cả các DifferentialDict instantiations chia sẻ cùng một từ điển cơ bản. Tôi có thể thêm một khóa 'cấp độ nhập cảnh' cho mỗi instantiationDict instantiation, nhưng cảm giác của tôi là có một giải pháp thanh lịch hơn mà eludes tôi.

Tôi thực sự đánh giá cao bất kỳ đề xuất nào về cách nhận từ điển vi phân hoạt động khi lồng nhau. Cảm ơn trước!

+0

Bài kiểm tra nào đang trôi qua và bài kiểm tra nào không thành công? – RafaelC

+0

Thử nghiệm 2 và 3 thất bại, 1 lần. –

+0

Tôi vừa tìm thấy thư viện này: [dictdiffer] (https: // github.com/inveniosoftware/dictdiffer) có thể đã thực hiện nó. Trên Hacker News có một cuộc thảo luận về nó, nơi raymondh cho thấy làm thế nào để làm điều này với các từ điển không lồng nhau [trong Python tinh khiết] (https://news.ycombinator.com/item?id=5771696). –

Trả lời

3

Tôi không có thời gian để thử này ngay bây giờ (có thể một chút sau), nhưng đây là hai quan sát:

kết hợp chỉ số

Nếu bạn sẽ sử dụng các bộ như chỉ số, ví dụ như điều này dict[(5,3,2)] bạn sẽ không có vấn đề này. Nếu bạn căn cứ vào căn cứ dict của bạn hoặc cũng có sự khác biệt dicts về điều này, bạn có thể phá vỡ vấn đề.

Có thể bạn thậm chí có thể viết một số lớp viết lại dict[a][b][c] thành dict[(a,b,c)] để thực hiện thay đổi nội bộ này trong suốt.

cơ sở toàn cầu

Tôi không hiểu tại sao bạn sử dụng cơ sở toàn cầu. Theo quan điểm của tôi, điều này làm cho mã phức tạp hơn mà không cần thêm bất kỳ thứ gì. Tại sao bạn không chỉ lưu trữ các cơ sở như trong:

def MyDict(collections.abc.MutableSequence): 
    def __init__(self, base): 
     self._base = base 

my_global_base = dict() 
d = MyDict(my_global_base) 

d[2] = 'abc' # modifies self._base inside of the instance too, because it is the 
      # same object 

Nếu bạn muốn thay đổi toàn bộ nội dung của các cơ sở, chỉ cần xóa tất cả các mục sử dụng popitem() và sau đó thêm những người mới sử dụng update(). Bằng cách này, mã của bạn linh hoạt hơn và không có bất kỳ hành vi đáng ngạc nhiên nào do các biến toàn cục.

lớp cơ sở trừu tượng

Khi reimplementing lớp như trình tự, từ điển vv nó có thể có ích để sử dụng abstract base classes cung cấp bởi Python, họ làm một số công việc thực hiện cho bạn.

+0

Cảm ơn, Georg. Theo như kết hợp các khóa trong một bộ dữ liệu có liên quan, tôi đã xem xét điều này, nhưng điều này dẫn đến một chuỗi khóa dài cho bất kỳ phần tử nào được lưu trữ trong từ điển, có vẻ như không hiệu quả w.r.t. với mục đích ban đầu là giảm dung lượng bộ nhớ. –

+0

Theo như cơ sở toàn cầu có liên quan, mục đích của điều này là nó được chia sẻ bởi tất cả các trường hợp của DifferentialDict. Từ gợi ý của bạn, tôi hiểu rằng một tham chiếu đến đối tượng cơ sở được truyền khi khởi tạo một đối tượng MyDict mới, chứ không phải là một bản sao cục bộ trong đối tượng MyDict được tạo ra. Điều này có đúng không? (có, kiến ​​thức/hiểu biết của tôi về điều này là không đầy đủ). –

+0

Và tôi sẽ xem xét các lớp cơ sở trừu tượng, cảm ơn đề xuất. –

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