2015-09-02 132 views
1

我正在創建一個函數,用於在對象(student1)內添加每個數組的標記(作業,測驗,測試)。隨着代碼嘗試添加「Lloyd」,肯定會出現錯誤。 我要檢查「名」的數據類型以便執行算術運算僅當關鍵是數。請建議。Python:如何檢查對象的鍵值對的數據類型?

student1 = { 
    "name": "Lloyd", 
    "homework": [90, 97, 75, 92], 
    "quiz": [88, 40, 94], 
    "test": [75, 90] 
}  

def eachSubjAverage(std):    
    for item in std:       
     total = sum(std[item]) #totalling each marks 
     std[item].append(total)  

     average_no = total/(len(std[item])-1) #averaging the marks 
     std[item].append(average_no) 

eachSubjAverage(student1) 
+0

注意,字典是沒有順序的,爲了將不是你所期望的順序,以便追加。 http://stackoverflow.com/questions/15479928/why-is-the-order-in-python-dictionaries-and-sets-arbitrary – Tim

+0

@Tim:代碼附加到列表,而不是字典 - FWIW,字典沒有一個「追加」方法。將平均值和總和附加到商標上仍然是一個糟糕的主意,但出於不同的原因... –

回答

6

一個XY problem的一個很明顯的情況下...

你真正的問題是一個錯誤的數據結構,以相同的方式存儲異質信息(學生的名字和它的標記)。該RightSolution(TM)是使用一個更好的數據結構,即:

student1 = { 
    "personal_infos" : { 
     "name": "Lloyd", 
    }, 
    "marks": { 
     "homework": [90, 97, 75, 92], 
     "quiz": [88, 40, 94], 
     "test": [75, 90] 
    }, 
    "totals": {} 
    "averages": {} 
    } 

}

一旦你有了這個,你沒有來測試你是否有一個字符串或num的值:

def eachSubjAverage(student):    
    for subject, marks in student["marks"].items():       
     total = sum(marks) #totalling each marks 
     student["totals"][subject] = total  
     average = total/(len(marks)) 
     student["averages"][subject] = average 

請注意,您可以以不同的佈局你的數據,每個主題,即:

student1 = { 
    "personal_infos" : { 
     "name": "Lloyd", 
    }, 
    "subjects": { 
     "homework": { 
      "marks" : [90, 97, 75, 92], 
      "total" : None, 
      "average" : None 
      }, 
     "quiz": { 
      "marks" : [88, 40, 94], 
      "total" : None, 
      "average" : None 
      }, 
     "test": { 
      "marks" : [75, 90], 
      "total" : None, 
      "average" : None 
      }, 
     }, 
} 


def eachSubjAverage(student):    
    for subject, data in student["subjects"].items():       
     total = sum(data["marks"]) #totalling each marks 
     data["total"] = total  
     average = total/(len(data["marks"])) 
     data["average"] = average 

請注意,如果您還沒有運要修復數據結構(外部數據或其他),您仍然要不想依賴於類型檢查(最好是脆弱的) - 您要測試密鑰本身,可以通過將主題名稱列入白名單或黑名單「非主體」的名字,即:

# blacklist non-subjects 
NON_SUBJECTS = ("name",) 

def your_func(student): 
    for key, value in student.items(): 
     if key in NON_SUBJECTS: 
      continue 
     compute_stuff_here() 

哦,是的:將在標記列表中的總平均也是搬起石頭砸自己的腳的好方法 - 一旦它的完成,你可以」告訴最後兩個「標記」是標記還是(總數,平均值)。

+0

謝謝布魯諾爲我提供了管理對象內(異構)信息的基本方法。我現在知道我的問題的xy性質。我將會採用這種方法,因爲它似乎是最有說服力的技術。 您提供瞭解決方案,我沒有修復數據結構的選項。我無法理解「是」還是「如果」的陳述。請原諒我的基本疑問。你能否提供我參考我的問題的解決方案?感謝您的親切支持! – madhur

+0

「我無法理解,如果陳述。」那麼這是基本的Python基礎知識 - 你不明白的是什麼? –

+0

抱歉打擾你。我現在明白了。 – madhur

-2

您可以檢查值是否是迭代:

hasattr(std[item], '__iter__') 

,然後檢查每個成員都是Number

all(map (lambda x: isinstance(x,numbers.Number), std[item])) 
+2

字符串不可迭代嗎? – Tim

+0

這取決於Python的版本,我擴展了我的答案 – igon

+0

仍嘗試修復錯誤的問題。真正的問題是一個不正確的數據結構,它混合了學生的個人信息(「姓名」)和主題標記... –

-2

你可以使用一個try except

for item in std: 
    try: 
     total = sum(std[item]) 
    except TypeError: 
     pass 
+0

然後有一天有人把一個字符串放在標記中(這是一個錯誤),並且代碼默默地通過而不是崩潰大聲 - 應該如此。 –

+0

@brunodesthuilliers啊,公平點。你的答案確實工作得更好:) – Tim

2
for item in std: 
    if isinstance(std[item],list): 
     total = sum(std[item]) 

如果你想確保在列表中的元素是int類型,那麼

for item in std: 
    if isinstance(std[item],list) and all(isinstance(e,int) for e in student1[item]): 
     total = sum(std[item]) 

瞭解isinstance()方法

+0

然後有一天,字典增長了一個不是標記的整數列表,並且它們被代碼處理。 –

+0

@brunodesthuilliers那不是我的問題嗎?我只是想回答這個問題。我想預測未來嗎? – taesu

1

有幾種方法可以檢查數據的值。 try/except結構看起來笨重,但有更短的方法。你可以使用功能type,它返回您的對象類型的

第一:

>>> type(student1['name']) == str 
True 
>>> type(student1['test']) == list 
True 

或者,使用非常簡單的一招。乘以任何對象爲零返回一個空對象,或者0,如果int

>>> student1['name']*0 == "" 
True 
>>> student1['test']*0 == [] 
True 
>>> student1['test'][1]*0 == 0 
True 
+0

'isinstance(obj,cls)'通常是比測試類型相等更好的選擇。哦,是的,'type'實際上是一個類,而不是一個函數。 –

+0

@Sdwdaw:感謝您的解決方案。我瞭解到,這不是最好的方法。雖然,它有一些警告,它解決了我的問題。 – madhur