Traceback (most recent call last):
File "people.py", line 7, in <module>
print(youngest_first([{"name": "Ada", "age": 36}, {"name": "Grace", "age": None}]))
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "people.py", line 3, in youngest_first
ordered = sorted(people, key=lambda person: person["age"])
TypeError: '<' not supported between instances of 'NoneType' and 'int'The same comparison error from max(), which also compares values inside itself. The traceback cannot show you max’s code, but it tells you what it met.
temperatures = [18, None, 21] # one reading missing print(max(temperatures)) # TypeError: '>' not supported between instances of 'int' and 'NoneType' known = [t for t in temperatures if t is not None] print(max(known)) # 21
- The line is innocent
max(temperatures) is correct code. When the error happens inside a built-in, the traceback stops at your line because there is no Python source further down to show.
- The message names the types
'int' and 'NoneType': one side is a number, the other is None. That is the whole diagnosis, and it points at the data, not the call.
- Decide what missing means
Dropping the None is right for a maximum. For a sorted list of people it is wrong: nobody should vanish from the register because a field is blank. Each problem decides for itself.
The last line says a NoneType was compared with an int. The key function hands sorted the ages, so which person has an age of None?
The key has to give every person something sorted can compare with every other key, and it has to put unknown ages after known ones.
Sort on a tuple: (age is None, age). False sorts before True, so known ages come first; and two unknowns compare equal on (True, None) without ever comparing None with anything.
ordered = sorted(people, key=lambda person: (person["age"] is ____, person["____"]))
def youngest_first(people):
"""Names ordered by age, youngest first."""
ordered = sorted(people, key=lambda person: (person["age"] is None, person["age"]))
return [person["name"] for person in ordered]
Tuples compare item by item. (False, 21) against (True, None) is decided by False < True alone, so a known age is never compared with None.
(True, None) against (True, None): the first items are equal, the second items are equal, and the tuples are equal. Python never needs None < None, and sorted keeps the two in their original order.
It reads naturally, and it fails twice: a real age of 0 is falsy and turns into 999, and 999 is a made-up age someone will one day exceed. The tuple says what is meant, unknown after known, without inventing a number.
If most records have missing fields, sorting is the wrong place to deal with it. Clean the data when it comes in, or keep unknowns in their own list, so every other part of the program does not need the same care.
- Sort oldest first, still with unknown ages last, and notice which part of the key cannot simply be reversed.
- Break age ties by name instead of by the order given.
- Return the unknowns as a separate list so the register can say whose age is missing.