Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python LIST functions not returning new lists

Tags:

python

list

I'm having an issue considering the built-in Python List-methods.

As I learned Python, I always thought Python mutators, as any value class mutators should do, returned the new variable it created.

Take this example:

a = range(5)
# will give [0, 1, 2, 3, 4]
b = a.remove(1)
# as I learned it, b should now be [0, 2, 3, 4]
# what actually happens:
# a = [0, 2, 3, 4]
# b = None

The main problem with this list mutator not returning a new list, is that you cannot to multiple mutations subsequently. Say I want a list ranging from 0 to 5, without the 2 and the 3. Mutators returning new variables should be able to do it like this:

a = range(5).remove(2).remove(3)

This sadly isn't possible, as range(5).remove(2) = None.

Now, is there a way to actually do multiple mutations on lists like I wanna do in my example? I think even PHP allows these types of subsequent mutations with Strings.

I also can't find a good reference on all the built-in Python functions. If anyone can find the actual definition (with return values) of all the list mutator methods, please let me know. All I can find is this page: http://docs.python.org/tutorial/datastructures.html

like image 266
Steven Roose Avatar asked Dec 02 '22 23:12

Steven Roose


2 Answers

Rather than both mutating and returning objects, the Python library chooses to have just one way of using the result of a mutator. From import this:

There should be one-- and preferably only one --obvious way to do it.

Having said that, the more usual Python style for what you want to do is using list comprehensions or generator expressions:

[x for x in range(5) if x != 2 and x != 3]

You can also chain these together:

>>> [x for x in (x for x in range(5) if x != 2) if x != 3]
[0, 1, 4]

The above generator expression has the added advantage that it runs in O(n) time because Python only iterates over the range() once. For large generator expressions, and even for infinite generator expressions, this is advantageous.

like image 131
Greg Hewgill Avatar answered Dec 17 '22 11:12

Greg Hewgill


Many methods of list and other mutable types intentionally return None so that there is no question in your mind as to whether you are creating a new object or mutating an existing object. The only thing that could be happening is mutation since, if a new object were created, it would have to be returned by the method, and it is not returned.

As you may have noticed, the methods of str that edit the string do return the new string, because strings are immutable and a new string is always returned.

There is of course nothing at all keeping you from writing a list subclass that has the desired behavior on .append() et al, although this seems like rather a heavy hammer to swing merely to allow you to chain method calls. Also, most Python programmers won't expect that behavior, making your code less clear.

like image 23
kindall Avatar answered Dec 17 '22 13:12

kindall