Traceback (most recent call last):
File "scores.py", line 7, in <module>
print(top_three([72, 95, 88, 61, 90]))
~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "scores.py", line 4, in top_three
return ranked[:3]
~~~~~~^^^^
TypeError: 'NoneType' object is not subscriptableThe same trap with append instead of sort. Watch what gets assigned, and what happens to the original list.
names = ["Grace", "Ada"]
result = names.append("Linus")
print(result) # None -- append changed names and returned nothing
print(names) # ['Grace', 'Ada', 'Linus']
print(result[0])
# TypeError: 'NoneType' object is not subscriptable
- None you did not write
Nobody typed None anywhere. A None you did not write comes from a function or method that returned nothing, and the list methods that change a list, append, extend, sort, reverse, all do exactly that.
- Look at the assignment, not the use
The crash is on result[0], but result[0] is fine code. The mistake is the line that set result, one line up, which the traceback does not show at all.
- In place means someone else’s list changed
names grew even though the code looked as if it was making a result. A method that works in place changes whatever list it is called on, including one the caller still owns.
The traceback says ranked is None. What does scores.sort(reverse=True) return? Try print(scores.sort()) on a small list.
sort() changes the list in place and returns None. sorted() returns a new sorted list and leaves the original alone, which is also what the contract asks for.
Build ranked with sorted(scores, reverse=True), then slice the first three. The caller’s list is never touched.
def top_three(scores): return ____(scores, reverse=____)[:3]
def top_three(scores):
"""The three highest scores, highest first."""
return sorted(scores, reverse=True)[:3]
sorted(scores) builds a new list and returns it; the caller’s list keeps its order. The obvious-looking fix, calling scores.sort() on its own line and then slicing, stops the crash and still reorders someone else’s data.
[:3] on a list of two gives the two, and on an empty list gives an empty list. No length check is needed for the short cases.
Sorting keeps every element, so three people on 7 fill the podium. Taking a set first would drop them to one, and nothing would crash to say so.
For three from a very long list, sorting everything is more work than needed: heapq.nlargest(3, scores) finds them without sorting the rest, and returns them highest first. Below a few thousand items the difference is not worth the import.
- Return names with the scores, from a list of (name, score) pairs, highest score first.
- Decide what a podium should do with a tie for third, and write it that way.
- Use heapq.nlargest and time it against sorted on a million scores.