简体   繁体   English

str(list)如何工作?

[英]How does str(list) work?

Why does str(list) returns how we see list on the console? 为什么str(list)返回我们在控制台上看到列表的方式? How does str(list) work? str(list)如何工作? (any reference to the CPython code for str(list) )? (对str(list)的CPython代码的任何引用)?

>>> x = ['abc', 'def', 'ghi']
>>> str(x)
"['abc', 'def', 'ghi']"

To get the original list back from the str(list) I have to: 要从str(list)获取原始列表,我必须:

>>> 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? 为什么没有list(str(list))str(list)转回原始列表?

Or I could use: 或者我可以使用:

>>> eval(str(x))
['abc', 'def', 'ghi']

Is literal_eval the same as eval ? literal_evaleval吗? Is eval safe to use? eval是否可以安全使用?

How many times can I do the following? 我可以多少次执行以下操作? Does the code break if it keep on doing str(list(str(list)))) ? 如果代码继续执行str(list(str(list)))) ,代码是否会中断? Eg 例如

>>> 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. 那么你总共有4个问题,让我们一个接一个。

1. Why does str(list) returns how we see list on the console? 1.为什么str(list)返回我们在控制台上看到list的方式? How does str(list) work? str(list)如何工作?

What is str() and __str__() ? 什么是str()__str__()

The str() callable is to return a printable form of the object only! str()可调用只返回对象的可打印形式! From the docs 来自文档

str(object) does not always attempt to return a string that is acceptable to eval() ; str(object)并不总是尝试返回eval()可接受的字符串; its goal is to return a printable string. 它的目标是返回一个可打印的字符串。

The __str__() function in a class is called whenever you call str() on an object. 只要在对象上调用str() ,就会调用类中的__str__()函数。 Again from the documentation 再次来自文档

object.__str__(self)

Called by the str() built-in function and by the print statement to compute the “informal” string representation of an object. str()内置函数和print语句调用,以计算对象的“非正式”字符串表示形式。

What is the list callable? 可调用的list是什么?

The list() callable is to create a list from an iterable passed as an argument. list()可调用是从作为参数传递的iterable创建一个列表。 Again from the docs 再次来自文档

Return a list whose items are the same and in the same order as iterable's items 返回一个list其项目与iterable的项目相同且顺序相同

Thus, str(list) gives you a printable form and list(str(list)) will iterate over the string. 因此, str(list)为您提供可打印的表单, list(str(list))将遍历字符串。 That is list(str(list)) will give you a list of the individual characters of the printable form of the argument passed. list(str(list))将为您提供所传递参数的可打印形式的各个字符的列表。

A small walk-through between the nested calls, 嵌套调用之间的一个小步骤,

Given list, l = ['a','b'] (Apologies for taking a smaller example than that in your question) . 给定列表, l = ['a','b'] (抱歉比你的问题更小的例子)

When you call str(l) , it returns a printable form of the list l , that is "['a','b']" . 当你调用str(l) ,它返回列表l的可打印形式,即"['a','b']"

Now you can see clearly that "['a','b']" is a string and is indeed an iterable . 现在你可以清楚地看到"['a','b']"是一个字符串,确实是一个可迭代的 Now when you call list on this ie list("['a','b']") you get a weird list like ['[', "'", 'a', "'", ',', "'", 'b', "'", ']'] . 现在,当您在此list上调用list list("['a','b']")您会得到一个奇怪的列表,如['[', "'", 'a', "'", ',', "'", 'b', "'", ']'] Why does this happen? 为什么会这样? This happens because the string iterates over its characters, you can test this by using a dummy string, 发生这种情况是因为字符串遍历其字符,您可以使用虚拟字符串对此进行测试,

>>> 'dummy'
'dummy'
>>> list('dummy')
['d', 'u', 'm', 'm', 'y']

Thus when you call the list on a string you get a list of character. 因此,当您在字符串上调用list时,您将获得一个字符列表。 Note that again here, when you call str() on list('dummy') , you will not get back your original string 'dummy' , so again you will have to use join ! 请注意,在这里,当你在list('dummy') str()上调用str()时,你不会得到原始字符串'dummy' ,所以你将不得不再次使用join 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? 那么,在列表上调用str()调用列表的builtin __str__()方法吗?

The answer is NO! 答案是不!

What happens internally when you call str() on a list? 当你在列表上调用str()时会发生什么?

Whenever you call str() on an list object, the steps followed are 无论何时在列表对象上调用str() ,遵循的步骤都是

  1. Call the repr() of each of the list element. 调用每个list元素的repr()
  2. Add a fancy [ at the front and another ] at the end of the list. 在列表的末尾添加一个[在前面和另一个]的花哨。
  3. Join all of them with a comma. 用逗号加入所有这些。

As you can see from the source code of the list object in cpython on github . 正如你可以从github上的cpython中的列表对象的源代码中看到的那样 Going through the source code of cpython in hg.python , which is more clear, you can see the following three comments. 在hg.python中查看cpython的源代码,更清楚的是,您可以看到以下三条注释。 (Thanks to Ashwini for the link on that particular code ) (感谢Ashwini关于该特定代码的链接)

 /* Do repr() on each element. Note that this may mutate the list, so must refetch the list size on each iteration. */ line (382) /* Add "[]" decorations to the first and last items. */ line (398) /* Paste them all together with ", " between. */ line (418) 

These correspond to the points I mentioned above. 这些对应于我上面提到的要点。

Now what is repr() ? 现在什么是repr()

repr() prints the string representation of all the objects. repr()打印所有对象的字符串表示形式。 Again from the documentation 再次来自文档

Return a string containing a printable representation of an object. 返回包含对象的可打印表示的字符串。

and also note this sentence! 还要注意这句话!

For many types, this function makes an attempt to return a string that would yield an object with the same value when passed to eval() , otherwise the representation is a string enclosed in angle brackets that contains the name of the type of the object together with additional information often including the name and address of the object. 对于许多类型,此函数尝试返回一个字符串,该字符串在传递给eval()时会产生具有相同值的对象,否则表示形式是一个用尖括号括起来的字符串,它包含对象类型的名称附加信息通常包括对象的名称和地址。

And now your second question here, 现在你的第二个问题,

2. Why doesn't list(str(list)) turns the str(list) back to the original list? 2.为什么没有list(str(list))str(list)转回原始列表?

Internally, str(list) actually creates the repr() representation of the list object. 在内部, str(list)实际上创建了列表对象的repr()表示。 So to get back the list after calling str on the list, you actually need to do eval on it and not a list call. 因此,要在列表上调用str后返回列表,您实际上需要对其执行eval而不是list调用。

Workarounds 解决方法

But we all know that eval is evil , so what is/are the workaround(s)? 但是我们都知道eval邪恶的 ,那么解决方法是什么?

1. Using literal_eval 1.使用literal_eval

The first work-around would be to use ast.literal_eval . 第一个解决方法是使用ast.literal_eval That brings us to your 3rd question, 这就把我们带到了你的第三个问题,

3. Is literal_eval() the same as eval() ? 3. literal_eval()eval()相同吗? Is eval() safe to use? eval()安全使用?

ast.literal_eval() is safe unlike the eval() function. eval()函数不同ast.literal_eval()是安全的。 The docs themselves mention that it is safe -- 文档本身提到它是安全的 -

Safely evaluate an expression node or a string containing a Python literal or container display 安全地评估表达式节点或包含Python文字或容器显示的字符串

2. Using string functions and builtins 2.使用字符串函数和内置函数

Another workaround can be done using str.split() 可以使用str.split()完成另一个解决方法

>>> x = ['abc', 'def', 'ghi']
>>> a = str(x)
>>> a[2:-2].split("', '")
['abc', 'def', 'ghi']

This is just a simple way to do that for a list of strings. 对于字符串列表,这只是一种简单的方法。 For a list of integers you will need map . 对于整数列表,您需要map

>>> x = [1,2,3]
>>> a =str(x)
>>> list(map(int,a[1:-1].split(', '))) # No need for list call in Py2
[1, 2, 3]

Thus unlike literal_eval these are simple hacks given that you know the elements of the list. 因此,与literal_eval不同,这些是简单的hacks,因为您知道列表的元素。 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. 如果它们本质上是异构的,如[1, "a", True]那么你将不得不遍历拆分列表并发现元素类型然后转换它并将转换后的元素附加到最终列表。

Another place where this fails is when the string itself contains quote characters. 另一个失败的地方是字符串本身包含引号字符。 As mentioned by nneonneo in a comment 正如nneonneo评论中提到的那样

The str.split solution is very fragile and will break if the input contains eg strings that contain ", " , or tuples, or other lists, ... It is much better to use ast.literal_eval because that will deal with all the subtleties of the syntax. str.split解决方案非常脆弱,如果输入包含例如包含", "或元组或其他列表的字符串,则会中断...使用ast.literal_eval要好得多,因为这将处理所有细微之处的语法。

And for your final question, 对于你的最后一个问题,

4. Does the code break if you do str(list(str(list)))) again and again? 4.如果你一次又一次地执行str(list(str(list)))) ,代码是否会中断?

Not really. 并不是的。 The output will grow longer and longer as each time you are creating a list of a str and then again getting the printable version of it. 每次创建str list然后再次获取它的可打印版本时,输出将变得越来越长。 The limitation is your physical machine's limitation only. 限制只是您的物理机器的限制。 (which will be soon reached as each step the string length is multiplied by 5.) (随着每一步将字符串长度乘以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) ; 列表不是最终用户可呈现的对象,并且您获得与repr(listobject)相同的输出; debug information for developer consumption only. 调试仅供开发人员使用的信息。

The list() callable creates a new list object from any arbitrary iterable object; list()可调用从任意可迭代对象创建一个新的列表对象; Python strings are iterable producing individual characters when you do so, list(stringobject) always produces a list with individual characters. Python字符串可以迭代生成单个字符, list(stringobject)总是生成一个包含单个字符的列表。

As such, list() will never attempt to interpret a string argument as Python syntax; 因此, list()永远不会尝试将字符串参数解释为Python语法; and doing so would not even work if the original list contained objects without a Python literal notation. 如果原始列表包含没有Python文字符号的对象,那么这样做甚至都不会起作用。 Take for example: 举个例子:

>>> def foo(): return 'bar'
... 
>>> alist = [foo]
>>> alist
[<function foo at 0x106c748c0>]

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. 您不能将该调试字符串输出转换回原始列表,特别是如果您在Python解释器中运行它,甚至没有定义这样的函数。

The str() function in python is used to turn a value into a string. python中的str()函数用于将值转换为字符串。 The simple answer to what the str() does to a list is that it creates a string representation of the list (square brackets and all). str()list的作用的简单答案是它创建list的字符串表示(方括号和所有)。

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. 至于list(str(list)) ,您所做的就是告诉python将原始列表转换为字符串,然后将该字符串拆分并将其放入列表中,以便每个索引都有一个字符。 So you could nest list and str calls as many times as you want (assuming your computer is has enough memory). 所以你可以根据需要多次嵌套liststr调用(假设你的计算机有足够的内存)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM