1

I'm coming from an R background and am confused about the following:

Suppose I had "hello" in list format saved in the variable txt. Thus

 txt=  ['h','e','l','l','o']

After some testing, the following works:

txt.reverse()
"."join(txt)

and produces as expected olleh.

However, the following does not work:

"".join(txt.reverse())

It gives an error. I'm curious why that is the case as I thought I can "nest" function calls within function calls?

Thank you for helping!

Vasif
  • 1,393
  • 10
  • 26
user1357015
  • 11,168
  • 22
  • 66
  • 111
  • 2
    You could use `reversed` instead: `"".join(reversed(txt))`. – Bakuriu Oct 16 '13 at 20:25
  • @roippi `reversed` *is* in-place. Try `reversed([1,2,3])` on the interpreter, it returns a `listreverseiterator` object which means *no copies are made*. The difference is that `.reverse()` modifies the original list, while `reversed()` iterates over it. – Bakuriu Oct 16 '13 at 20:28
  • @Bakuriu yep. Haven't had my coffee today. "in place" (or the inverse) is a bad description for any sort of iterator. – roippi Oct 16 '13 at 20:29
  • @Bakuriu That just means `reversed` returns an iterator that will return the items in reverse order. It does not modify the original argument, which the `reverse` method does. – chepner Oct 16 '13 at 20:29
  • @chepner It depends on what you define by "in-place". My definition is "an operation that uses `O(1)` memory", which is the algorithmic definition. I believe to express the other meaning it would be better to speak of *side-effects* or of *copies*, which is more explicit than "in-place". For example `sequence.sort()` is in-place, meaning that it has side-effects, but not in-place, meaning that it takes `O(1)` memory. Better differentiate between the two. – Bakuriu Oct 16 '13 at 20:34
  • As a side note, if you were only storing the string in a list to reverse it, a better idea is to simply reverse the string as-is: `a = "hello"; b = a[::-1]; print b # 'olleh'`. For an explanation of that check out slice notation in python. (You can also do that on your list... `"".join(txt[::-1])`) – SethMMorton Oct 16 '13 at 20:35
  • What does the `in place`means? – ovrwngtvity Oct 16 '13 at 20:45
  • 1
    @viddhart - Here is an explanation: http://stackoverflow.com/questions/5317817/python-in-place-functions –  Oct 16 '13 at 23:31

5 Answers5

5

The problem is that the reverse() function does not return an useful value (it returns None), because it reverses the list in-place, as a way to avoid the need to create a new output list. So this:

"".join(txt.reverse())

... Will try to join None, which clearly will fail.

Óscar López
  • 232,561
  • 37
  • 312
  • 386
5

Being an in-place function, the reverse method of a list always returns None:

>>> a = [1, 2]
>>> print a.reverse()
None
>>> a
[2, 1]
>>>

You can get the behavior you want by using the reversed built-in:

>>> a = ['a', 'b']
>>> "".join(reversed(a))
'ba'
>>> a
['a', 'b']
>>>
  • Maybe also show the unmodified value of `a` in the `reversed` example, as you did the modified value of `a` in the `reverse` one? – Peter DeGlopper Oct 16 '13 at 20:29
  • Awesome, this is EXACTLY what was confusing me. In R, it's pretty much always an object that's returned, so I never had to worry about it. Makes complete sense. Thank you again. – user1357015 Oct 16 '13 at 20:32
  • @user1357015 In python operations that have side-effects usually do *not* return a value(i.e. they return `None`). Conversely, functions that return a value usually do *not* have side-effects. It's a convention used pretty often. By the way: you can always obtain R behaviour using some `or`s: `"".join(txt.reverse() or txt)`. `txt.reverse()` returns `None`, which is considered false, so python will evaluate `txt` and return it instead(return values of `or` and `and` need *not* be booleans). However this seems quite dirty. – Bakuriu Oct 16 '13 at 20:36
3

your problem is that txt.reverse() does NOT return the reversed list, it returns None,

ie, txt.reverse() reverses your list in place

Cameron Sparr
  • 3,925
  • 2
  • 22
  • 31
2

You can use reversed instead:

".".join(reversed(txt))
zero323
  • 322,348
  • 103
  • 959
  • 935
1

As already said the list.reverse() replaces the list in-place, thus returns None

If you want a nestable version you can use the reversed function

In [7]: "".join(reversed(txt))
Out[7]: 'olleh'
Jakob
  • 19,815
  • 6
  • 75
  • 94