2012-02-20 13 views
5

Próbuję zachować słownik otwartych plików do podziału danych na poszczególne pliki. Kiedy żądam pliku ze słownika, chciałbym go otworzyć, jeśli klucza tam nie ma. Jednak nie wygląda na to, że mogę użyć lambda jako domyślnej.czy możliwe jest użycie lambda jako domyślnego słownika?

np.

files = {} 
for row in data: 
    f = files.get(row.field1, lambda: open(row.field1, 'w')) 
    f.write('stuff...') 

Nie działa, ponieważ f jest ustawione na funkcję, a nie na jej wynik. setdefault przy użyciu powyższej składni też nie działa. Czy mogę coś zrobić oprócz tego:

f = files.get(row.field1) 
if not f: 
    f = files[row.field1] = open(row.field1, 'w') 

Odpowiedz

7

ten przypadek użycia jest zbyt skomplikowane dla defaultdict, dlatego nie wierzę, że coś takiego istnieje w stdlib Pythona. Można jednak łatwo napisać rodzajowy „rozszerzone” defaultdict siebie, która przechodzi brakujący klucz do callback:

from collections import defaultdict 

class BetterDefaultDict(defaultdict): 
    def __missing__(self, key): 
    return self.setdefault(key, self.default_factory(key)) 

Zastosowanie:

>>> files = BetterDefaultDict(lambda key: open(key, 'w')) 
>>> files['/tmp/test.py'] 
<open file '/tmp/test.py', mode 'w' at 0x7ff552ad6db0> 

Działa to w Pythonie 2.7+, nie wiem o starsze wersje :) Ponadto, nie zapomnij, aby ponownie zamknąć te pliki:

finally: 
    for f in files.values(): f.close() 
2

można owinąć get-a-otwarty w klasie obiektu __getitem__() dość łatwo - coś Li KE:

class FileCache(object): 
    def __init__(self): 
     self.map = {} 

    def __getitem__(self,key): 
     if key not in self.map:    
      self.map[key] = open(key,'w') 
     return self.map.key 
1

Inną opcją dla podklasy, że powinien zrobić to, czego potrzebujesz:

class LambdaDefaultDict(dict): 

    def get(self, key, default=None): 
     try: 
      return self[key] 
     except KeyError: 
      return default() 

    def setdefault(self, key, default=None): 
     if not self.has_key(key): 
      self[key] = default() if default else None 
     return self[key] 

Albo, być może bardziej ogólnie - w celu umożliwienia ustawienia domyślne, które to wartości lub wyrażenia wywoływalne:

class CallableDefaultDict(dict): 

    def get(self, key, default=None): 
     try: 
      return self[key] 
     except KeyError: 
      return default() if callable(default) else default 

    def setdefault(self, key, default=None): 
     if not self.has_key(key): 
      self[key] = default() if callable(default) else default 
     return self[key] 
1

Możesz użyć defaultdict z modułu kolekcji

class FileCache(collections.defaultdict): 
    def __missing__(self, key): 
    fo = open(key, 'w') 
    self[key] = fo 
    return fo 

Choć może lepiej byłoby po prostu zrobić

files = {} 
def get_file(f): 
    fo = files.get(f) 
    if fo is None: 
    fo = open(f, 'w') 
    files[f] = fo 
    return fo 

for row in data: 
    f = get_file(row.field1) 
    f.write('stuff...') 
1

To jest dokładnie powód dict[key] składnia podnosi KeyError:

files = {} 
for row in data: 
    f = files.get(row.field1, lambda: open(row.field1, 'w')) 
    f.write('stuff...') 

powinny stać się:

files = {} 
for row in data: 
    try: f = files[row.field1] 
    except KeyError: f = open(row.field1, 'w') 
    f.write('stuff...') 
+1

get() nie podnieść kluczowy błąd, jeśli przedmiot nie zostanie znaleziony. [] notacja robi. na przykład pliki [klucz] – Jacob

Powiązane problemy