I’m interested in the thought process that led to this. To me, a relative newbie, it seems hampering, since it prevents “chaining” of list processing (e.g. mylist.reverse().append('a string')[:someLimit]). I imagine it might be that “The Powers That Be” decided that list comprehension is a better paradigm (a valid opinion), and so didn’t want to encourage other methods – but it seems perverse to prevent an intuitive method, even if better alternatives exist.
Note that I’m not complaining (I’m sure there is a sensible reason, I’m just interested in what it is!), nor looking for a solution (the comments here were very instructive) – just looking for some context, and a deeper understanding of the language’s design process.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
The general design principle in Python is for functions that mutate an object in-place to return None. I’m not sure it would have been the design choice I’d have chosen, but it’s basically to emphasise that a new object is not returned.
Guido van Rossum (our Python BDFL) states the design choice here: http://mail.python.org/pipermail/python-dev/2003-October/038855.html)
I’d like to explain once more why I’m so adamant that sort() shouldn’t
return ‘self’.This comes from a coding style (popular in various other languages, I
believe especially Lisp revels in it) where a series of side effects
on a single object can be chained like this:x.compress().chop(y).sort(z)which would be the same as
x.compress() x.chop(y) x.sort(z)I find the chaining form a threat to readability; it requires that the
reader must be intimately familiar with each of the methods. The
second form makes it clear that each of these calls acts on the same
object, and so even if you don’t know the class and its methods very
well, you can understand that the second and third call are applied to
x (and that all calls are made for their side-effects), and not to
something else.I’d like to reserve chaining for operations that return new values,
like string processing operations:y = x.rstrip("n").split(":").lower()There are a few standard library modules that encourage chaining of
side-effect calls (pstat comes to mind). There shouldn’t be any new
ones; pstat slipped through my filter when it was weak.
Method 2
I can’t speak for the developers, but I find this behavior very intuitive.
If a method works on the original object and modifies it in-place, it doesn’t return anything, because there is no new information – you obviously already have a reference to the (now mutated) object, so why return it again?
If, however, a method or function creates a new object, then of course it has to return it.
So l.reverse() returns nothing (because now the list has been reversed, but the identfier l still points to that list), but reversed(l) has to return the newly generated list because l still points to the old, unmodified list.
EDIT: I just learned from another answer that this principle is called Command-Query separation.
Method 3
One could argue that the signature itself makes it clear that the function mutates the list rather than returning a new one: if the function returned a list, its behavior would have been much less obvious.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0