I am creating a function to add the marks of each array(homework, quiz, test) inside an object(student1). There definitely arises errors as the code tries to add "Lloyd". I want to check the data-type of value of "name" so as to carry the arithmetic operation only if the value of the key is number. Please Suggest.
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)
An obvious case of a XY problem ...
Your real problem is a wrong data structure that stores heterogenous informations (the student's name and it's marks) the same way. The RightSolution(tm) is to use a better data structure, ie:
student1 = {
"personal_infos" : {
"name": "Lloyd",
},
"marks": {
"homework": [90, 97, 75, 92],
"quiz": [88, 40, 94],
"test": [75, 90]
},
"totals": {}
"averages": {}
}
}
Once you have this, you don't have to test whether you have a string or num as value:
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
Note that you could layout your data differently, ie per subject:
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
Note that if you don't have the option to fix the data structure (external data or else), you still don't want to rely on type-checking (which is brittle at best) - you want to test the key itself, either by whitelisting the subjects names or blacklisting the "non-subjects" names, ie:
# 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()
Oh and yes: adding the total and average in the marks list is also a good way to shoot yourself in the foot - once it's done, you can't tell wether the last two "marks" are marks or (total, average).
for item in std:
if isinstance(std[item],list):
total = sum(std[item])
if you want to make sure that the elements in the list is of type int
, then
for item in std:
if isinstance(std[item],list) and all(isinstance(e,int) for e in student1[item]):
total = sum(std[item])
learn about isinstance() method
There are a few methods to check the value of the data. try/except
construction looks bulky, but there are more shorter ways.
First of all you can use function type
, which returns you type of the object:
>>> type(student1['name']) == str
True
>>> type(student1['test']) == list
True
Or, to use a very simple trick. Multiplying any object to zero returns an empty object or 0 if int
:
>>> student1['name']*0 == ""
True
>>> student1['test']*0 == []
True
>>> student1['test'][1]*0 == 0
True
You can check whether the value is iterable:
hasattr(std[item], '__iter__')
and then check that each member is a Number :
all( map ( lambda x: isinstance(x,numbers.Number), std[item] ) )
You could use a try except
:
for item in std:
try:
total = sum(std[item])
except TypeError:
pass
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.