-2

Was solving an algorithms problem and had to reverse a list. When done, this is what my code looked like:

def construct_path_using_dict(previous_nodes, end_node):
    constructed_path = []
    current_node = end_node
    while current_node:
        constructed_path.append(current_node)
        current_node = previous_nodes[current_node]
    constructed_path = reverse(constructed_path)    
    return constructed_path

But, along the way, I tried return constructed_path.reverse() and I realized it wasn't returning a list... Why was it made this way?
Shouldn't it make sense that I should be able to return a reversed list directly, without first doing list.reverse() or list = reverse(list) ?

DonCarleone
  • 544
  • 11
  • 20
  • technically, you can still return it in a single line by converting an iterator to a list using `list()`. For ex. `return list(original_list.reverse())` .Alternatively, `return reversed(original_list)`. I do admit that my comment addresses only a technical aspect, I am not sure exactly why developers decided to return an iterator from `list.reverse()` – Alex.Kh Nov 20 '20 at 00:02
  • What is `reverse(constructed_path)` supposed to be? There is no built-in `reverse` function. – user2357112 Nov 20 '20 at 00:22
  • 2
    `mylist.reverse()` works *in-place*, modifying the list, and as is conventionally the case for mutator methods, returns `None` in Python. So all you need is `constructed_path.reverse()` – juanpa.arrivillaga Nov 20 '20 at 00:24
  • @user2357112supportsMonica my mistake, I meant `reversed()` – Alex.Kh Nov 20 '20 at 00:31
  • @Alex.Kh I think you meant `reverse(list)`.. with the _ed_ you may be thinking of `sorted(list)`. Made the same mixup haha! – DonCarleone Nov 20 '20 at 01:21
  • @DonCarleone. Sometimes the naming convention lets me down. Because I mixed the `sorted()` method, I made a mistake in my comment. A built-in `reversed()` function(or rather a class) returns a reverse iterator and you have to use a `list()` to convert it into a list while `list.reverse()` does it in place. You did get a correct answer already but I wanted to correct a mistake on my part. Do `help(reversed)` to check the documentation – Alex.Kh Nov 20 '20 at 02:52
  • Does this answer your question? [list.reverse does not return list?](https://stackoverflow.com/questions/4280691/list-reverse-does-not-return-list) – user202729 Dec 20 '21 at 05:19

3 Answers3

5

What I'm about to write was already said here, but I'll write it anyway because I think it will perhaps add some clarity.

You're asking why the reverse method doesn't return a (reference to the) result, and instead modifies the list in-place. In the official python tutorial, it says this on the matter:

You might have noticed that methods like insert, remove or sort that only modify the list have no return value printed – they return the default None. This is a design principle for all mutable data structures in Python.

In other words (or at least, this is the way I think about it) - python tries to mutate in-place where-ever possible (that is, when dealing with an immutable data structure), and when it mutates in-place, it doesn't also return a reference to the list - because then it would appear that it is returning a new list, when it is really returning the old list.

To be clear, this is only true for object methods, not functions that take a list, for example, because the function has no way of knowing whether or not it can mutate the iterable that was passed in. Are you passing a list or a tuple? The function has no way of knowing, unlike an object method.

FoolsWisdom
  • 821
  • 4
  • 6
3

list.reverse reverses in place, modifying the list it was called on. Generally, Python methods that operate in place don’t return what they operated on to avoid confusion over whether the returned value is a copy.

You can reverse and return the original list:

constructed_path.reverse()
return constructed_path

Or return a reverse iterator over the original list, which isn’t a list but doesn’t involve creating a second list just as big as the first:

return reversed(constructed_path)

Or return a new list containing the reversed elements of the original list:

return constructed_path[::-1]
# equivalent: return list(reversed(constructed_path))

If you’re not concerned about performance, just pick the option you find most readable.

Ry-
  • 218,210
  • 55
  • 464
  • 476
2

methods like insert, remove or sort that only modify the list have no return value printed – they return the default None. 1 This is a design principle for all mutable data structures in Python.

PyDocs 5.1

As I understand it, you can see the distinction quickly by comparing the differences returned by modifying a list (mutable) ie using list.reverse() and mutating a list that's an element within a tuple (non-mutable), while calling

id(list)

id(tuple_with_list)

before and after the mutations. Mutable data-type mutations returning none is part allowing them to be changed/expanded/pointed-to-by-multiple references without reallocating memory.

Jim
  • 96
  • 1
  • 6