I have a quick question about an issue I discovered. In the Python shell I can write test1 = "hello".upper() and when I type test1 I get "HELLO", as expected. However, if I do something similar with a list, such as test2 = ["hello", "world"].reverse(), and I try to return test2, I get nothing; it is a "NoneType" with no value assigned to it. Why does this happen? Why can I make an assignment with a method acting on a string but I can't make an assignment when there is a method acting on a list?
6 Answers
It's because list.reverse() reverses in place. This means it returns None, so when you do test2 = ["hello", "world"].reverse(), you're assigning the result of .reverse() (None) to test2.
Comments
First, strings are immutable, while lists are mutable. This means you can change an existing list object:
>>> l = [1,2,3]
>>> id(l)
140370614775608
>>> l.append(4)
>>> l
[1,2,3,4]
>>> id(l)
140370614775608
You cannot change a string object, however; you can only create a new string object using the first as a starting point.
>>> s1 = "hello"
>>> id(s1)
140370614929376
>>> s1.upper()
'HELLO'
>>> id(s1)
140370614929376
In Python, the convention is that a method either modifies an object and returns None, or returns a new, modified object while leaving the original alone.
1 Comment
The reason that you can sometimes do one thing with one object and not do something different with a different object is that different objects and different methods are different. The documentation for each method says what it does. You need to look at the documentation for the individual method you are using to see what it does. There is no reason to assume that someString.upper() will work like someList.reverse(), because strings are not lists, and upper is not reverse.
1 Comment
.upper() returns a new string, which you assign to test1. The string you operated on ("hello") is not modified. Indeed, it couldn't be since strings are immutable in Python.
.reverse() modifies in-place. That means the object ["hello", "world"] got modified. Unfortunately, you don't have a variable pointing to that object, so you can't see that.
This is a convention in Python. Functions that modify in-place return None, whereas functions that create a modified copy return that copy.
Comments
.upper() returns a new String object, on the contrary, .reverse() is a destructive method, which means that the receiver is changed forever.
For reversing a list you can use
test2 = ["hello", "world"][::-1]
which would work for strings too:
In [1]: test2 = ["hello", "world"][::-1]
In [2]: test2
Out[2]: ['world', 'hello']
In [3]: test2 = "world"[::-1]
In [4]: test2
Out[4]: 'dlrow'
Functional constructs are built into the language and not in methods.
upper()has to return a new string. Lists are mutable so many operations are done inplace, e.g.reverse()List.__add__creates a new list.pop,index,count, etc.None.