# Why does ‘.sort()’ cause the list to be ‘None’ in Python? [duplicate]

Posted on

### Question :

Why does ‘.sort()’ cause the list to be ‘None’ in Python? [duplicate]

I am attempting to sort a Python list of `int`s and then use the `.pop()` function to return the highest one. I have tried a writing the method in different ways:

``````def LongestPath(T):
paths = [Ancestors(T,x) for x in OrdLeaves(T)]
#^ Creating a lists of lists of ints, this part works
result =[len(y) for y in paths ]
#^ Creating a list of ints where each int is a length of the a list in paths
result = result.sort()
#^meant to sort the result
return result.pop()
#^meant to return the largest int in the list (the last one)
``````

I have also tried

``````def LongestPath(T):
return[len(y) for y in [Ancestors(T,x) for x in OrdLeaves(T)] ].sort().pop()
``````

In both cases `.sort()` causes the list to be `None` (which has no `.pop()` function and returns an error). When I remove the `.sort()` it works fine but does not return the largest `int` since the list is not sorted.

Simply remove the assignment from

``````result = result.sort()
``````

leaving just

``````result.sort()
``````

The `sort` method works in-place (it modifies the existing list), so no assignment is necessary, and it returns `None`. When you assign its result to the name of the list, you’re assigning `None`.

It can easily (and more efficiently) be written as a one-liner:

``````max(len(Ancestors(T,x)) for x in OrdLeaves(T))
``````

`max` operates in linear time, O(n), while sorting is O(nlogn). You also don’t need nested list comprehensions, a single generator expression will do.

This

``````result = result.sort()
``````

should be this

``````result.sort()
``````

It is a convention in Python that methods that mutate sequences return `None`.

Consider:

``````>>> a_list = [3, 2, 1]
>>> print a_list.sort()
None
>>> a_list
[1, 2, 3]

>>> a_dict = {}
>>> print a_dict.__setitem__('a', 1)
None
>>> a_dict
{'a': 1}

>>> a_set = set()
None
>>> a_set
set([1])
``````

Python’s Design and History FAQ gives the reasoning behind this design decision (with respect to lists):

Why doesn’t `list.sort(`) return the sorted list?

In situations where performance matters, making a copy of the list
just to sort it would be wasteful. Therefore, `list.sort()` sorts the
list in place. In order to remind you of that fact, it does not return
the sorted list. This way, you won’t be fooled into accidentally
overwriting a list when you need a sorted copy but also need to keep
the unsorted version around.

In Python 2.4 a new built-in function – `sorted()` – has been added.
This function creates a new list from a provided iterable, sorts it
and returns it.

`.sort()` returns None and sorts the list in place.

This has already been correctly answered: `list.sort()` returns `None`. The reason why is “Command-Query Separation”:

http://en.wikipedia.org/wiki/Command-query_separation

Python returns `None` because every function must return something, and the convention is that a function that doesn’t produce any useful value should return `None`.

I have never before seen your convention of putting a comment after the line it references, but starting the comment with a carat to point at the line. Please put comments before the lines they reference.

While you can use the `.pop()` method, you can also just index the list. The last value in the list can always be indexed with `-1`, because in Python negative indices “wrap around” and index backward from the end.

But we can simplify even further. The only reason you are sorting the list is so you can find its max value. There is a built-in function in Python for this: `max()`

Using `list.sort()` requires building a whole list. You will then pull one value from the list and discard it. `max()` will consume an iterator without needing to allocate a potentially-large amount of memory to store the list.

Also, in Python, the community prefers the use of a coding standard called PEP 8. In PEP 8, you should use lower-case for function names, and an underscore to separate words, rather than CamelCase.

http://www.python.org/dev/peps/pep-0008/

With the above comments in mind, here is my rewrite of your function:

``````def longest_path(T):
paths = [Ancestors(T,x) for x in OrdLeaves(T)]
return max(len(path) for path in paths)
``````

Inside the call to `max()` we have a “generator expression” that computes a length for each value in the list `paths`. `max()` will pull values out of this, keeping the biggest, until all values are exhausted.

But now it’s clear that we don’t even really need the `paths` list. Here’s the final version:

``````def longest_path(T):
return max(len(Ancestors(T, x)) for x in OrdLeaves(T))
``````

I actually think the version with the explicit `paths` variable is a bit more readable, but this isn’t horrible, and if there might be a large number of paths, you might notice a performance improvement due to not building and destroying the `paths` list.

`list.sort()` does not return a list – it destructively modifies the list you are sorting:

``````In [177]: range(10)
Out[177]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [178]: range(10).sort()

In [179]:
``````

That said, `max` finds the largest element in a list, and will be more efficient than your method.

In Python `sort()` is an inplace operation. So `result.sort()` returns `None`, but changes `result` to be sorted. So to avoid your issue, don’t overwrite `result` when you call `sort()`.

Is there any reason not to use the sorted function? `sort()` is only defined on lists, but `sorted()` works with any iterable, and functions the way you are expecting. See this article for sorting details.

Also, because internally it uses timsort, it is very efficient if you need to sort on key 1, then sort on key 2.

You don’t need a custom function for what you want to achieve, you first need to understand the methods you are using!

`sort()`ing a list in python does it in place, that is, the return from `sort()` is `None`. The list itself is modified, a new list is not returned.

``````>>>results = ['list','of','items']
>>>results

['list','of','items']

>>>results.sort()
>>>type(results)

<type 'list'>

>>>results

['items','list','of']

>>>results = results.sort()
>>>results
>>>
>>>type(results)

<type 'NoneType'>
``````

As you can see, when you try to assign the `sort()` , you no longer have the list type.