2012-07-28 13 views
8

Mam słownik zawierający słowniki, które mogą również zawierać słowniki, np.Python - wartości dostępu zagnieżdżone w słownikach

dictionary = {'ID': 0001, 'Name': 'made up name', 'Transactions': 
       {'Transaction Ref': 'a1', 'Transaction Details': 
        {'Bill To': 'abc', 'Ship To': 'def', 'Product': 'Widget A' 
         ...} ...} ... } 

Obecnie jestem rozpakowaniu dostać „Bill” dla ID 001, a1 „transakcja Sygn” następująco:

if dictionary['ID'] == 001: 
    transactions = dictionary['Transactions'] 
     if transactions['Transaction Ref'] == 'a1': 
      transaction_details = transactions['Transaction Details'] 
      bill_to = transaction_details['Bill To'] 

nie mogę pomóc, ale że to jest trochę clunky, zwłaszcza dwie ostatnie linie - czuję się jak coś wzdłuż linii następujących powinno działać:

bill_to = transactions['Transaction Details']['Bill To'] 

Czy istnieje prostsze podejście do wiercenia w dół do zagnieżdżonych słowników bez konieczności rozpakowania do inter im zmienne?

+6

Linia czujesz powinny działać właściwie robi. –

Odpowiedz

13
bill_to = transactions['Transaction Details']['Bill To'] 

faktycznie działa. transactions['Transaction Details'] jest wyrażeniem oznaczającym dict, więc można w nim wyszukiwać. W przypadku programów praktycznych wolałbym jednak podejście OO do zagnieżdżonych dyktatur. collections.namedtuple jest szczególnie przydatny do szybkiego konfigurowania grup klas, które zawierają tylko dane (i nie zachowują się samodzielnie).

Jest jeszcze jedna uwaga: w niektórych ustawieniach, może chcesz złapać KeyError robiąc wyszukiwań, w tym ustawieniu, który działa też trudno powiedzieć, który słownik lookup failed:

try: 
    bill_to = transactions['Transaction Details']['Bill To'] 
except KeyError: 
    # which of the two lookups failed? 
    # we don't know unless we inspect the exception; 
    # but it's easier to do the lookup and error handling in two steps 
+0

Niezwykle pomocna - wielkie dzięki! – user1530213

20

Można użyć coś takiego:

>>> def lookup(dic, key, *keys): 
...  if keys: 
...   return lookup(dic.get(key, {}), *keys) 
...  return dic.get(key) 
... 
>>> d = {'a':{'b':{'c':5}}} 
>>> print lookup(d, 'a', 'b', 'c') 
5 
>>> print lookup(d, 'a', 'c') 
None 

Dodatkowo, jeśli nie chcemy, aby zdefiniować swoje klucze wyszukiwania w postaci poszczególnych parametrów, można po prostu przekazać je w postaci listy jak ten:

>>> print lookup(d, *['a', 'b', 'c']) 
5 
>>> print lookup(d, *['a', 'c']) 
None 
+0

Mam nadzieję, że nie masz nic przeciwko, dodałem edycję, aby wyjaśnić prawdziwą funkcję dynamicznego wyszukiwania tej funkcji. Możliwość przekazywania listy kluczy wyszukiwania w locie sprawia, że ​​jest to skrót od innych technik. –

2

Poniżej inny sposób uzyskiwania dostępu zagnieżdżone słowniki

>>> dbo={'m':{'d':{'v':{'version':1}}}} 
>>> name='m__d__v__version' # it'll refer to 'dbo['m']['d']['v']['version']', '__' is the separator 
>>> version = reduce(dict.get, name.split('__'), dbo) 
>>> print version 
1 
>>> 

Tutaj, zmienna 'Nazwa' odnosi się do 'dbo [' m '] [' d '] [' V '] [' wersja '] ", który wydaje się znacznie krótszy i schludny.

Ta metoda nie rzuci KeyError. Jeśli klucz nie zostanie znaleziony, dostaniesz "Brak".

Ref .: http://code.activestate.com/recipes/475156-using-reduce-to-access-deeply-nested-dictionaries/

+0

Wyrzuci TypeError jeśli spróbujesz name = 'm__foo__v__foo': TypeError: deskryptor 'get' wymaga obiektu 'dict', ale otrzymał 'NoneType' – krasnaya

Powiązane problemy