str(list)如何工作?

alv*_*vas 12 python string eval list python-internals

为什么str(list)返回我们在控制台上看到列表的方式?str(list)工作怎么样?(对CPython代码的任何引用str(list))?

>>> x = ['abc', 'def', 'ghi']
>>> str(x)
"['abc', 'def', 'ghi']"
Run Code Online (Sandbox Code Playgroud)

要获得原始列表,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']
Run Code Online (Sandbox Code Playgroud)

为什么不list(str(list))转动str(list)回原来的名单?

或者我可以使用:

>>> eval(str(x))
['abc', 'def', 'ghi']
Run Code Online (Sandbox Code Playgroud)

literal_eval一样的eval吗?是否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', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ']']
Run Code Online (Sandbox Code Playgroud)

Bha*_*Rao 60

那么你总共有4个问题,让我们一个接一个.

1.为什么str(list)返回我们list在控制台上看到的内容?str(list)工作怎么样?

什么是str()__str__()

str()调用是返回一个可打印的仅为对象的形式!来自文档

str(object)并不总是试图返回一个可接受的字符串eval(); 它的目标是返回一个可打印的字符串.

__str__()无论何时调用str()对象,都会调用类中的函数.再次来自文档

object.__str__(self)

str()内置函数和print语句调用以计算对象的"非正式"字符串表示.

什么是list可赎回的?

list()调用是创建作为参数传递一个迭代的列表.再次来自文档

返回list其项目与iterable项目相同且顺序相同的项目

因此,str(list)为您提供可打印的表单,list(str(list))并将迭代字符串.这list(str(list))将为您提供所传递参数的可打印形式的各个字符的列表.

嵌套调用之间的一个小步骤,

给出列表,l = ['a','b'] (抱歉比你的问题更小的例子).

当你打电话时str(l),它会返回列表的可打印形式l,即"['a','b']".

现在你可以清楚地看到这"['a','b']"是一个字符串,确实是一个可迭代的.现在,当你调用list这个也就是list("['a','b']")你得到一个奇怪的名单一样['[', "'", 'a', "'", ',', "'", 'b', "'", ']'].为什么会这样?发生这种情况是因为字符串遍历其字符,您可以使用虚拟字符串对其进行测试,

>>> 'dummy'
'dummy'
>>> list('dummy')
['d', 'u', 'm', 'm', 'y']
Run Code Online (Sandbox Code Playgroud)

因此,当您调用liston字符串时,您将获得一个字符列表.请注意,在这里,当你打电话str()list('dummy'),你将不会收回原来的字符串'dummy',所以你必须再次使用join!因此,回忆相同的功能不会让你回到原来的对象!

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

答案是不!

当您呼叫str()列表时,内部会发生什么?

无论何时调用str()列表对象,遵循的步骤都是

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

正如你可以从github上的cpython中的列表对象的源代码中看到的那样.在hg.python中查看cpython的源代码,更清楚的是,您可以看到以下三条注释.(感谢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)
Run Code Online (Sandbox Code Playgroud)

这些对应于我上面提到的要点.

现在是什么repr()

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

返回包含对象的可打印表示的字符串.

还要注意这句话!

对于许多类型,此函数尝试返回一个字符串,该字符串在传递时会产生具有相同值的对象eval(),否则表示形式是一个括在尖括号中的字符串,其中包含对象类型的名称以及其他信息通常包括对象的名称和地址.

现在你的第二个问题,

2.为什么不list(str(list))转动str(list)回原来的名单?

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

解决方法

但我们都知道这eval邪恶的,那么解决方法是什么?

1.使用 literal_eval

第一个解决方法是使用ast.literal_eval.这就把我们带到了你的第三个问题,

3.是literal_eval()一样的eval()吗?是否eval()安全使用?

ast.literal_eval()eval()功能不同是安全的.文档本身提到它是安全的 -

安全地评估表达式节点或包含Python文字或容器显示的字符串

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

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

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

对于字符串列表,这只是一种简单的方法.有关您需要的整数列表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]
Run Code Online (Sandbox Code Playgroud)

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

另一个失败的地方是字符串本身包含引号字符.正如nneonneo评论中提到的那样

str.split解决方案是很脆弱的,如果输入中包含了含有如字符串将打破", ",或元组,或其他列表,...这是更好的使用ast.literal_eval,因为这将涉及语法的所有细微之处.

对于你的最后一个问题,

4.如果你str(list(str(list))))一次又一次地执行代码会破坏代码吗?

并不是的.输出将增长越来越长,因为每个要创建一个时间liststr,然后再得到它的打印版本.限制只是您的物理机器的限制.(随着每一步将字符串长度乘以5,将很快到达)


Mar*_*ers 6

您似乎期望从列表中创建字符串是可循环访问的.它并不意味着; 列表不是最终用户可呈现的对象,您获得相同的输出repr(listobject); 调试仅供开发人员使用的信息.

list()调用创建从任意迭代的对象一个新的列表对象; Python字符串是可迭代的,当您这样做时会产生单个字符,list(stringobject)总是生成一个包含单个字符的列表.

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

>>> def foo(): return 'bar'
... 
>>> alist = [foo]
>>> alist
[<function foo at 0x106c748c0>]
Run Code Online (Sandbox Code Playgroud)

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