2012-05-25 12 views
9

Chciałbym stworzyć strukturę danych, która zachowuje się jak słownik z jedną dodaną funkcjonalnością, która ma na celu śledzenie, które klucze zostały "zużyte". Pamiętaj, że nie mogę po prostu użyć wartości, ponieważ są ponownie używane.Słownik języka Python z pamięcią kluczy, do których uzyskano dostęp?

Struktura powinna wspierać te trzy przypadki, tj oznaczyć klucz do spożycia, gdy dostępne jako:

if key in d: 
    ... 
d[key] 
d.get(key) 

To co napisałem:

class DictWithMemory(dict): 

    def __init__(self, *args, **kwargs): 
     self.memory = set() 
     return super(DictWithMemory, self).__init__(*args, **kwargs) 

    def __getitem__(self, key): 
     self.memory.add(key) 
     return super(DictWithMemory, self).__getitem__(key) 

    def __contains__(self, key): 
     self.memory.add(key) 
     return super(DictWithMemory, self).__contains__(key) 

    def get(self, key, d=None): 
     self.memory.add(key) 
     return super(DictWithMemory, self).get(key, d) 

    def unused_keys(self): 
     """ 
     Returns the list of unused keys. 
     """ 
     return set(self.keys()).difference(self.memory) 

Ponieważ nie jestem bardzo obeznany z wewnętrznym dyktowaniem, czy istnieje lepszy sposób na osiągnięcie tego rezultatu?

+1

jak często można użyć 'unused_keys()' ? jeśli udekorowałeś settera, aby dodał klucze do zestawu, a getter spróbowałby usunąć klucze z tego zestawu, mógłbyś mieć lepszą wydajność - nie wiesz o części ** elegance **, pomyślał – Aprillion

+2

Poza tym: dlaczego 'nieużywane_keys' powinny zwracać lista? Nie ma wewnętrznego porządku, więc ma sens, aby zwrócić zestaw. –

+0

@Thomas K: Ze względu na symetrię, 'keys' zwraca listę. – badzil

Odpowiedz

4

Oto rozwiązanie, które usuwa wszystko z wnętrza metaclasu. Nie jestem pewien, czy to jest naprawdę bardziej elegancki, ale daje pewną ilość enkapsulacji należy zmienić zdanie na temat sposobu przechowywania zużytych klawiszy:

class KeyRememberer(type): 

    def __new__(meta, classname, bases, classDict): 
     cls = type.__new__(meta, classname, bases, classDict) 

     # Define init that creates the set of remembered keys 
     def __init__(self, *args, **kwargs): 
      self.memory = set() 
      return super(cls, self).__init__(*args, **kwargs) 
     cls.__init__ = __init__ 

     # Decorator that stores a requested key in the cache 
     def remember(f): 
      def _(self, key, *args, **kwargs): 
       self.memory.add(key) 
       return f(self, key, *args, **kwargs) 
      return _ 

     # Apply the decorator to each of the default implementations 
     for method_name in [ '__getitem__', '__contains__', 'get' ]: 
      m = getattr(cls, method_name) 
      setattr(cls, method_name, remember(m)) 

     return cls 


class DictWithMemory(dict): 

    # A metaclass that ensures the object 
    # has a set called 'memory' as an attribute, 
    # which is updated on each call to __getitem__, 
    # __contains__, or get. 
    __metaclass__ = KeyRememberer 

    def unused_keys(self): 
     """ 
     Returns the list of unused keys. 
     """ 
     print "Used", self.memory 
     return list(set(super(DictWithMemory, 
           self).keys()).difference(self.memory)) 
+1

Podoba mi się korzystanie z metaclass do ograniczenia, które pozwala na dynamiczną konfigurację, które metody są uważane za "konsumentów". – badzil

+0

Zgadzam się z komentarzem @ badzil i myślę, że być może powinien pójść jeszcze dalej i pozwolić swoim klientom zdefiniować lub unieważnić, które metody są uważane za konsumentów - w funkcji Myślę, że można łatwo dodać. – martineau

Powiązane problemy