Why does str(list)
returns how we see list on the console? How does str(list)
work? (any reference to the CPython code for str(list)
)?
>>> x = ['abc', 'def', 'ghi']
>>> str(x)
"['abc', 'def', 'ghi']"
To get the original list back from the str(list)
I have to:
>>> from ast import literal_eval
>>> x = ['abc', 'def', 'ghi']
>>> str(x)
"['abc', 'def', 'ghi']"
>>> list(str(x))
['[', "'", 'a', 'b', 'c', "'", ',', ' ', "'", 'd', 'e', 'f', "'", ',', ' ', "'", 'g', 'h', 'i', "'", ']']
>>> literal_eval(str(x))
['abc', 'def', 'ghi']
Why doesn't list(str(list))
turns the str(list)
back to the original list?
Or I could use:
>>> eval(str(x))
['abc', 'def', 'ghi']
Is literal_eval
the same as eval
? Is eval
safe to use?
How many times can I do the following? Does the code break if it keep on doing str(list(str(list))))
? E.g.
>>> x = 'abc'
>>> list(x)
['a', 'b', 'c']
>>> str(list(x))
"['a', 'b', 'c']"
>>> list(str(list(x)))
['[', "'", 'a', "'", ',', ' ', "'", 'b', "'", ',', ' ', "'", 'c', "'", ']']
>>> str(list(str(list(x))))
'[\'[\', "\'", \'a\', "\'", \',\', \' \', "\'", \'b\', "\'", \',\', \' \', "\'", \'c\', "\'", \']\']'
>>> list(str(list(str(list(x)))))
['[', "'", '[', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", 'a', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", 'b', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", 'c', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ']']
>>> str(list(str(list(str(list(x))))))
'[\'[\', "\'", \'[\', "\'", \',\', \' \', \'"\', "\'", \'"\', \',\', \' \', "\'", \'a\', "\'", \',\', \' \', \'"\', "\'", \'"\', \',\', \' \', "\'", \',\', "\'", \',\', \' \', "\'", \' \', "\'", \',\', \' \', \'"\', "\'", \'"\', \',\', \' \', "\'", \'b\', "\'", \',\', \' \', \'"\', "\'", \'"\', \',\', \' \', "\'", \',\', "\'", \',\', \' \', "\'", \' \', "\'", \',\', \' \', \'"\', "\'", \'"\', \',\', \' \', "\'", \'c\', "\'", \',\', \' \', \'"\', "\'", \'"\', \',\', \' \', "\'", \']\', "\'", \']\']'
>>> list(str(list(str(list(str(list(x)))))))
['[', "'", '[', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '[', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", 'a', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", 'b', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", 'c', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ']']
Well you have a total of 4 questions, let us go one by one.
What is
str()
and__str__()
?The
str()
callable is to return a printable form of the object only! From the docsThe
__str__()
function in a class is called whenever you callstr()
on an object. Again from the documentationWhat is the
list
callable?The
list()
callable is to create a list from an iterable passed as an argument. Again from the docsThus,
str(list)
gives you a printable form andlist(str(list))
will iterate over the string. That islist(str(list))
will give you a list of the individual characters of the printable form of the argument passed.A small walk-through between the nested calls,
Given list,
l = ['a','b']
(Apologies for taking a smaller example than that in your question).When you call
str(l)
, it returns a printable form of the listl
, that is"['a','b']"
.Now you can see clearly that
"['a','b']"
is a string and is indeed an iterable. Now when you calllist
on this i.e.list("['a','b']")
you get a weird list like['[', "'", 'a', "'", ',', "'", 'b', "'", ']']
. Why does this happen? This happens because the string iterates over its characters, you can test this by using a dummy string,Thus when you call the
list
on a string you get a list of character. Note that again here, when you callstr()
onlist('dummy')
, you will not get back your original string'dummy'
, so again you will have to usejoin
! Thus recalling the same function will NOT get you back your original object!So, Calling
str()
over a list calls the builtin__str__()
method of the list?The answer is NO!
What happens internally when you call
str()
on a list?Whenever you call
str()
on an list object, the steps followed arerepr()
of each of the list element.[
at the front and another]
at the end of the list.As you can see from the source code of the list object in cpython on github.Going through the source code of cpython in hg.python, which is more clear, you can see the following three comments. (Thanks to Ashwini for the link on that particular code)These correspond to the points I mentioned above.
Now what is
repr()
?repr()
prints the string representation of all the objects. Again from the documentationand also note this sentence!
And now your second question here,
Internally,
str(list)
actually creates therepr()
representation of the list object. So to get back the list after callingstr
on the list, you actually need to doeval
on it and not alist
call.Workarounds
But we all know that
eval
is evil, so what is/are the workaround(s)?1. Using
literal_eval
The first work-around would be to use
ast.literal_eval
. That brings us to your 3rd question,ast.literal_eval()
is safe unlike theeval()
function. The docs themselves mention that it is safe --2. Using string functions and builtins
Another workaround can be done using
str.split()
This is just a simple way to do that for a list of strings. For a list of integers you will need
map
.Thus unlike
literal_eval
these are simple hacks given that you know the elements of the list. If they are heterogeneous in nature like[1, "a", True]
then you will have to loop through the split list and discover the element type and then convert it and append the converted element to a final list.Another place where this fails is when the string itself contains quote characters. As mentioned by nneonneo in a comment
And for your final question,
Not really. The output will grow longer and longer as each time you are creating a
list
of astr
and then again getting the printable version of it. The limitation is your physical machine's limitation only. (which will be soon reached as each step the string length is multiplied by 5.)You appear to have the expectation that creating a string from a list is round-trippable. It is not meant to be; lists are not end-user presentable objects and you get the same output as
repr(listobject)
; debug information for developer consumption only.The
list()
callable creates a new list object from any arbitrary iterable object; Python strings are iterable producing individual characters when you do so,list(stringobject)
always produces a list with individual characters.As such,
list()
will never attempt to interpret a string argument as Python syntax; and doing so would not even work if the original list contained objects without a Python literal notation. Take for example:You cannot take that debug string output and turn that back into the original list, especially if you run this in a Python interpreter where there is not even such a function defined.
The
str()
function in python is used to turn a value into a string. The simple answer to what thestr()
does to alist
is that it creates a string representation of the list (square brackets and all).As for the
list(str(list))
, all you are doing is telling python to convert the original list to a string then you are splitting that string and putting it into a list so that each index has one character. So you could nestlist
andstr
calls as many times as you want (assuming your computer is has enough memory).