str(list)如何工作?

时间:2015-05-07 18:32:29

标签: python string list eval python-internals

为什么str(list)会返回我们在控制台上看到列表的方式? 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', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', "'", '"', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", '"', "'", ',', ' ', "'", ',', "'", ',', ' ', "'", ' ', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ',', ' ', '"', "'", '"', ',', ' ', "'", ']', "'", ']']

3 个答案:

答案 0 :(得分:58)

嗯,你总共有4个问题,让我们一个接一个。

  

<强> 1。为什么str(list)会返回我们在控制台上看到list的方式? str(list)如何运作?

什么是str()__str__()

str() callable只返回对象的可打印形式!来自docs

  

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

只要在对象上调用__str__(),就会调用类中的str()函数。再次来自documentation

  

object.__str__(self)

     

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

list可调用什么?

list() callable是从作为参数传递的iterable创建一个列表。再次来自docs

  

返回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']

因此,当您在字符串上调用list时,您将获得一个字符列表。请注意,此处,当您在str()上致电list('dummy')时,您将无法取回原始字符串'dummy',因此您将不得不再次使用join!因此,回忆相同的功能将 NOT 让你回到原始对象!

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

答案是否定的!

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

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

  1. 调用每个列表元素的repr()
  2. 在前面添加一个花哨的[,在列表的末尾添加另一个]
  3. 用逗号加入所有这些内容。
  4. 正如您在cpython on github中的列表对象的源代码中所看到的那样。hg.python中查看cpython的源代码,更清楚,你可以请参阅以下三条评论。 (感谢Ashwini关于该特定code)的链接

    /* 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

      

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

    还要注意这句话!

      

    对于许多类型,此函数尝试返回字符串   传递给eval()时会产生具有相同值的对象,   否则表示是用尖括号括起来的字符串   它包含对象类型的名称   其他信息通常包括的名称和地址   对象

    现在你的第二个问题,

      

    <强> 2。为什么不list(str(list))str(list)转回原始列表?

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

    的变通方法

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

    1。使用literal_eval

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

      

    第3。 literal_eval()eval()相同吗? eval()可以安全使用吗?

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

      

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

    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

    中的comment所述
      

    str.split解决方案非常脆弱,如果输入包含例如包含", "或元组或其他列表的字符串......使用ast.literal_eval要好得多,因为这会处理语法的所有细微之处。

    对于你的最后一个问题,

      

    <强> 4。如果您一次又一次str(list(str(list)))),代码是否会中断?

    不是真的。每次创建list str然后再次获取其可打印版本时,输出将变得越来越长。限制只是您的物理机器的限制。 (将很快到达,因为每个步骤的字符串长度乘以5。)

答案 1 :(得分:6)

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

list() callable从任意可迭代对象创建一个新的列表对象; Python字符串可以迭代生成单个字符,list(stringobject)总是生成一个包含单个字符的列表。

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

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

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

答案 2 :(得分:3)

python中的str()函数用于将值转换为字符串。 str()list的作用的简单答案是它创建了列表的字符串表示(方括号和全部)。

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