2016-03-01 33 views
5

Inspyred kütüphanesi ve Genetic Algorithms uygulamasını kullanarak tasarım optimizasyonu için bir kod yazdım. Özünde, optimizasyon süreci, benim durumumda iç içe bir sözlük olan tek bir veri yapısı üzerinde çok sayıda varyasyon yaratır.Yalnızca değişiklikleri depolayan Python sözlüğü

İşlemde kullanılan bellek miktarını azaltmak için, yalnızca temel sözlükten farklı öğeleri depolayan bir tür farklı sözlük türü oluşturmaya çalışıyorum. Bunun nedeni, tipik bir durumda, veri yapısındaki verilerin% 95'inin herhangi bir varyasyonda değiştirilmeyeceğidir, ancak veri yapısının herhangi bir kısmı varyasyonlar içerebilir. Bu yüzden esneklik nedenlerinden ötürü, bir sözlük gibi aşağı yukarı hareket eden bir veri tipine sahip olmak istiyorum, ancak sadece değişiklikleri depolar.

Bu

bu oluşturmak için benim girişimi sonucudur:

#!/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() 

Basit bir sözlük için çalışıyor, ancak yeni sözlükleri ana sözlük içinde yuvalanmış zaman ayırır. Bunun, bu ikinci düzey sözlüklerin benim DifferentialDict örneğim yerine gerçek Python sözlükleri olduğu ve bunun, self.changes'teki değişikliklerden ziyade global_base'deki girdilerin üzerine yazılmasına yol açtığını anlıyorum. Bununla birlikte, tüm DiferansiyelDict örneklemelerinin aynı temel sözlüğü paylaştığı öncülünden dolayı olması gerekir. Her bir DifferentialDict örneğine bir 'giriş seviyesi' anahtarı ekleyebilirim, ama benim hislerim, beni yok eden daha zarif bir çözümün olması.

Farklı sözlüklerimin yuvalandığında nasıl çalışacağına dair önerileri gerçekten takdir ediyorum. Şimdiden teşekkürler!

+0

Hangi testler geçiyor ve hangileri başarısız oluyor? – RafaelC

+0

Test 2 ve 3 başarısız, 1 geçiş. –

+0

Bu kütüphaneyi yeni buldum: [dictdiffer] (https: // github.zaten uygulayabilen com/inveniosoftware/dictdiffer). raymondh [Saf Python] olmayan iç içe sözlükleri bunun nasıl göründüğü yeri Hacker News bununla ilgili bir tartışma var (https://news.ycombinator.com/item?id=5771696). –

cevap

3

Şimdi (belki biraz sonra) bu hakkı denemek için zamanım yok, ama burada iki gözlemler şunlardır:

kombine indeksleri

sizin gibi örneğin endeksler olarak dizilerini kullanmak istiyorsanız Bu dict[(5,3,2)] bu sorunu olmazdı. Temel kararınızı ya da bununla ilgili farklı açıları temel alırsanız, sorunu atlatabilirsiniz.

Belki bu iç değişikliği saydam yapmak için dict[a][b][c] yeniden dict[(a,b,c)] yeniden yazabilirsiniz bazı sınıflar yazabilirsiniz.

Eğer küresel bir üs kullanmak neden anlamıyorum

küresel tabanı. Benim bakış açımdan, bu kod bir şey eklemeden daha karmaşık hale getirir. Eğer baz tüm içeriği değiştirmek isterseniz sadece popitem() kullanarak tüm öğeleri silmek,

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 

ve sonra update() kullanarak yenilerini ekleyin: Neden sadece olduğu gibi tabanını saklamayın. Bu şekilde kodunuz daha esnektir ve küresel değişkenler nedeniyle şaşırtıcı bir davranışa sahip değildir.

soyut temel sınıfları

dizileri gibi sınıflar reimplementing, sözlükler vb Python tarafından sağlanan abstract base classes kullanmak işe yarayabilir, onlar sizin için uygulama çalışmalar yapmak.

+0

Teşekkürler, Georg. Bir tuple anahtarların birleştirilmesiyle ilgili olarak, bunu dikkate aldım, ancak bu, sözlükte saklanan herhangi bir eleman için uzun bir anahtar diziyle sonuçlanır ve bu da verimsiz gibi görünür. bellek ayak izini azaltmanın asıl amacına. –

+0

Küresel taban söz konusu olduğunda, bunun amacı, DifferentialDict'ın tüm örnekleri tarafından paylaşılmasıdır. Önerinizden, temel nesneye yapılan bir referansın, MyDict nesnesi içindeki yerel bir kopyanın oluşturulmasından ziyade yeni bir MyDict nesnesinin başlatılması üzerine geçtiğini anlıyorum. Bu doğru mu? (evet, benim bilgim/bunun anlayışı eksiktir). –

+0

Ve soyut temel sınıflarına bir göz atacağım, öneri için teşekkürler. –

İlgili konular