Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I am attempting to sort a Python list of ints 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.

like image 492
Btuman Avatar asked Mar 19 '12 20:03

Btuman


People also ask

Does sorted mutate the list?

🔸 Summary of the sort() Method reverse determines if the list is sorted in ascending or descending order. key is a function that generates an intermediate value for each element, and this value is used to do the comparisons during the sorting process. The sort() method mutates the list, causing permanent changes.

Why does .append print None?

append() method returns None because it mutates the original list. Most methods that mutate an object in place return None in Python.

Why does my list say none in Python?

Functions often print None when we pass the result of calling a function that doesn't return anything to the print() function. All functions that don't explicitly return a value, return None in Python.

What does sort () return in Python?

Python sorted() Function The sorted() function returns a sorted list of the specified iterable object. You can specify ascending or descending order. Strings are sorted alphabetically, and numbers are sorted numerically.


2 Answers

Simply remove the assignment from

result = result.sort()

leaving just

result.sort()

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


But in any case, what you're trying to accomplish 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.

like image 128
agf Avatar answered Oct 26 '22 07:10

agf


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.

like image 24
steveha Avatar answered Oct 26 '22 07:10

steveha