2016-07-12 121 views
2

我讀來自外部源的字典,讓我們說Python從字典中取值的最佳方式是什麼?

data = {'name': 'James', 'gender': 'male'} 

有時

data = {'name': 'James', 'gender': 'male', 'article': {'title':'abc'}} 

有時

data = {'name': 'James', 'gender': 'male', 'article': None} 

我知道,我可以使用.get(key, default)的時候我不知道如果數據中存在articles

articles = data.get('article', {}).get('title') 

但有時候,他們所提供的元素與None值,因此上述不工作而造成的錯誤,並且需要成爲:

articles = data.get('article') or {} 

但是這需要我把它分解成2條語句代替如前所述鏈接從文章中獲取價值。

有沒有更優雅的方式來做到這一點,是這樣的:

data.get('article', {}, ignore=[None]) 

data.get_ignore_none('article', {}) 
+0

您可能想要顯示數據在**有**條目時會顯示的方式,並說它可能不存在而不是相反。正如你所寫的你的例子'數據'和你正在做的事似乎完全不相關。 –

+0

因此,最終,你希望'data [「article」] [「title」]'作爲字符串值,或None,沒有錯誤? – Keith

+0

哪個Python版本? – jpmc26

回答

1

首先,你似乎認爲使用or表達丟棄false-y resultsdata.get('article')只能在兩個語句來完成類似如下:

temp = data.get('article') or {} 
articles = temp.get("title") 

但是,您可以將第一個表達式的括號括起來,並直接調用.get("title")它的返回值:

articles = (data.get('article') or {}).get("title") 

但我覺得這不是特別可讀或有效率,當'article'丟失或None,那麼你正在創建一個新的映射,並檢查它"title"不必要的。

一個可能的解決方案是使用像下面這樣的函數:

def nested_get(mapping, *keys): 
    """gets a value from a nested dictionary, 
if any key along the way is missing or None then None is returned 
will raise an AttributeError if a value in the chain is not a dictionary (support the .get method)""" 
    current = mapping 
    for item in keys: 
     current = current.get(item) 
     if current is None: 
      return None 
    return current 

然後你會做nested_get(data, "article", "title"),試圖讓data["article"]["title"]沒有拋出錯誤,如果data["article"]是無或丟失。

我用下面的代碼測試此:

test_cases = [{'name': 'James', 'gender': 'male'}, 
       {'name': 'James', 'gender': 'male', 'article': {'title':'abc'}}, 
       {'name': 'James', 'gender': 'male', 'article': None}] 

for case in test_cases: 
    print(case) 
    print(nested_get(case,"article","title")) 
    print() 

#the follwing will raise an error since mapping["a"] would need to be a dict 
nested_get({"a":5}, "a","b") 
+1

我認爲'articles =(data.get('article')or {})。get(「title」)'是迄今爲止最好的選擇,但是對於下一個人來說,目的評論。 –

+0

@JamesLin編輯是否足夠?我不是那種複合表達式的狂熱粉絲,因爲它並不是立即顯而易見的。 –

+0

我認爲函數方法會起作用,我會將其更改爲'nested_get(obj,(('article',{}),('authors',[])))'以允許指定默認變量。 –

2

默認.get()將返回None如果該鍵不存在。在你的情況下,你正在返回一個空字典。

現在,我不知道發生了什麼錯誤,但我確定它從get_stuff(article)而不是您的列表理解。

你有幾個方法來解決這個問題:

  1. 修改get_stuff,使其直接取值,而不是每個元素。這樣,你只是通過它[get_stuff(value) for value in data.get('articles')]。現在,在get_stuff,你只需做到這一點:

    [get_stuff(foo) for foo in data.get('articles') if data.get('articles')] 
    
+3

他得到的錯誤可能是'TypeError:'NoneType'對象不可迭代',當該關鍵字在字典中時,其值爲None – Copperfield

+1

我不明白你在理解中添加一個條件,會檢查循環中的每一次迭代,以便在'articles'存在和序列時進行不必要的檢查,或者如果'articles'丟失,它仍會引發TypeError。 –

+0

@BurhanKhalid我已經更新了我的問題,所以你的回答可能看起來有點過時,對於混淆抱歉。 –

0

這個怎麼樣

>>> data = {1:(42,23)} 
>>> [x for x in data.get(1) or []] 
[42, 23] 
>>> [x for x in data.get(32) or []] 
[] 

使用or改變:

def get_stuff(foo): 
    if not foo: 
    return None 
    for item in foo: 
    do stuff 
    return normal_results 
  • 在列表理解添加過濾器如果你得到None或者其他的東西,你的默認值LSE

    編輯

    以同樣的方式,你可以or和支架,以獲得在一行

    articles = (data.get('article') or {}).get('title') 
    

    ,並只是你處理三種情況下都需要的輸出。

    ,你還可以定義get_ignore_none例如像

    def get_ignore_none(data_dict, key, default=None): 
        if key in data_dict: 
         value = data_dict[key] 
         return value if value is not None else default 
        return default 
    
  • 2

    沒有什麼錯誤使用例外在這種情況下月初爆發。無論數據是什麼,我都假設你想要標題值或None。以下函數可以工作(對於Python 3)。

    def get_title(d): 
        try: 
         return data.get("article").get("title") 
        except AttributeError: 
         return None 
    

    如果外部字典獲取None作爲值或默認情況下它將引發您剛剛捕獲的None對象的AttributeError。

    +0

    是的使用異常是好的,但想象一下,當你處理像'文章'這樣的字段時,你會有很多try catch塊,看起來有點冗長。 –

    +2

    這是4行。不要被冗長的癱瘓。這已經處理「文章」。 – Keith

    +0

    4行很好,但正如我前面提到的,如果我處理的是像'文章'這樣的元素,它會變得冗長。 –

    0

    既然你從外部源加載此數據,一種選擇是一個預處理步驟只要你加載:

    from collections import Mapping 
    
    def remove_none(d): 
        for k, v in d.items(): 
         if v is None: 
          del d[k] 
         if isinstance(v, Mapping): 
          remove_none(v) 
    
    data = load_data_from_somewhere() 
    remove_none(data) 
    

    現在你可以使用get無處不在,你需要:

    articles = data.get('article', {}).get('title') 
    
    +0

    我認爲這與我想要做的很接近,我的例子有點微不足道,有時候這個問題深藏在字典的內部......是的,你可以遍歷字典,但我認爲它不夠明確。 –

    相關問題