str(list) 是如何工作的?

How does str(list) work?

为什么 str(list) returns 我们如何在控制台上看到列表? str(list) 是如何工作的? (对 str(list) 的 CPython 代码的任何引用)?

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

要从 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']

为什么 list(str(list)) 不将 str(list) 转回原始列表?

或者我可以使用:

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

literal_evaleval一样吗? eval 使用安全吗?

我可以执行以下操作多少次?如果代码继续执行 str(list(str(list)))),代码会中断吗? 例如

>>> 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', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ']']

你一共有4个问题,我们一一解答。

1. Why does str(list) returns how we see list on the console? How does str(list) work?

什么是str() and __str__()

str() 可调用对象仅是 return 可打印 形式的对象!来自 docs

str(object) does not always attempt to return a string that is acceptable to eval(); its goal is to return a printable string.

只要您在对象上调用 str(),就会调用 class 中的 __str__() 函数。再次来自 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.

什么是 list 可调用项?

list() 可调用函数是从作为参数传递的可迭代对象创建一个列表。再次来自 docs

Return a list whose items are the same and in the same order as iterable‘s items

因此,str(list) 为您提供了一个可打印的表单,而 list(str(list)) 将遍历该字符串。即 list(str(list)) 将为您提供所传递参数的可打印形式的单个字符列表。

嵌套调用之间的小走查,

给定列表,l = ['a','b'] (很抱歉举了一个比你问题中的小的例子)

当您调用 str(l) 时,它 return 是列表 l 的可打印形式,即 "['a','b']"

现在可以清楚地看到"['a','b']"是一个字符串,确实是一个iterable。现在当你调用 list 时,即 list("['a','b']") 你会得到一个奇怪的列表,比如 ['[', "'", 'a', "'", ',', "'", 'b', "'", ']']为什么会这样?这是因为字符串遍历了它的字符,你可以使用虚拟字符串来测试,

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

因此,当您在字符串上调用 list 时,您会得到一个字符列表。请再次注意,当您在 list('dummy') 上调用 str() 时,您将不会取回原始字符串 'dummy',因此您将不得不再次使用 join!因此,调用相同的函数 不会 让您找回原来的对象!

那么,在列表上调用 str() 会调用列表的内置 __str__() 方法吗?

答案是否定的!

当您在列表中调用 str() 时内部会发生什么?

每当您在列表对象上调用 str() 时,遵循的步骤是

  1. 调用每个列表元素的repr()
  2. 在列表的前面添加一个花哨的 [,在列表的末尾添加另一个 ]
  3. 用逗号连接所有这些。

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 )

中list对象的源码可以看出
/* 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)

这些都对应了我上面提到的几点

现在什么是repr()

repr() 打印所有对象的字符串表示形式。再次来自 documentation

Return a string containing a printable representation of an object.

还要注意这句话!

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.

现在你的第二个问题,

2. Why doesn't list(str(list)) turns the str(list) back to the original list?

在内部,str(list) 实际上创建了列表对象的 repr() 表示。因此,要在列表上调用 str 后取回列表,您实际上需要对其执行 eval 而不是 list 调用。

解决方法

但我们都知道 eval is evil,那么 is/are 解决方法是什么?

1。使用 literal_eval

第一个解决方法是使用 ast.literal_eval。这就引出了你的第三个问题,

3. Is literal_eval() the same as eval()? Is eval() safe to use?

ast.literal_eval() is safe unlike eval() 函数。文档本身提到它是安全的——

Safely evaluate an expression node or a string containing a Python literal or container display

2。使用字符串函数和内置函数

另一种解决方法可以使用 str.split()

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

这只是对字符串列表执行此操作的一种简单方法。对于整数列表,您需要 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]

因此,与 literal_eval 不同的是,如果您知道列表的元素,这些都是简单的技巧。如果它们本质上是异构的,例如 [1, "a", True] 那么您将不得不遍历拆分列表并发现元素类型,然后将其转换并将转换后的元素附加到最终列表。

另一个失败的地方是字符串本身包含引号字符。如nneonneo in a

所述

The str.split solution is very fragile and will break if the input contains e.g. 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.

最后一个问题,

4. Does the code break if you do str(list(str(list)))) again and again?

不是真的。每次您创建 strlist 然后再次获取它的可打印版本时,输出会越来越长。该限制只是您的物理机器的限制。 (随着字符串长度的每一步乘以 5,很快就会达到。)

您似乎期望从列表创建字符串是可往返的。这不是故意的;列表不是最终用户可呈现的对象,您得到与 repr(listobject) 相同的输出;仅供开发人员使用的调试信息。

list() 可调用函数从任意可迭代对象创建一个新的列表对象; Python 字符串可迭代生成单个字符,list(stringobject) 始终生成包含单个字符的列表。

因此,list() 永远不会尝试将字符串参数解释为 Python 语法;如果原始列表包含没有 Python 文字符号的对象,那么这样做甚至不会起作用。举个例子:

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

您不能获取调试字符串输出并将其转换回原始列表,尤其是如果您 运行 在 Python 解释器中使用它甚至没有定义这样的函数。

python中的str()函数用于将一个值转为字符串。 str()list 的作用的简单答案是它创建列表的字符串表示形式(方括号和所有)。

至于 list(str(list)),您所做的只是告诉 python 将原始列表转换为字符串,然后拆分该字符串并将其放入列表中,以便每个索引都有一个字符。因此,您可以根据需要嵌套 liststr 调用(假设您的计算机有足够的内存)。