在Python中拆分字符串时,Value解包的奇怪行为

时间:2013-12-14 02:17:24

标签: python string split list-comprehension

用例:我有一个由换行符分隔的长字符串,每行有两个用逗号分隔的元素。

理想情况下,这应该有效

[(x, y) for line in lines.split() for x, y in line.split(',')]

但它没有,并产生与下面相同的ValueError。所以我试图分解问题来弄清楚这里发生了什么

lines = \
"""a,b
c,d
e,f
g,h"""

lines = [line for line in lines.split()]

print(lines)
print(len(lines))
print([len(line) for line in lines])
print(all(',' in line for line in lines))

[(x, y) for l in lines for x,y in l.split(',')]

收率:

/usr/bin/python3m /home/alex/PycharmProjects/test.py
['a,b', 'c,d', 'e,f', 'g,h']
4
[3, 3, 3, 3]
True

Traceback (most recent call last):
File "/home/alex/PycharmProjects/test.py", line 74, in <module>
...
File "/home/alex/PycharmProjects/test.py", line 63, in <listcomp>
[(x, y) for l in sines for x,y in l.split(',')]
ValueError: need more than 1 value to unpack

然而,如果我用经典的for循环替换最后一行中的列表理解:

for line in lines:
x, y = line.split(',')

成功执行:

['a,b', 'c,d', 'e,f', 'g,h']
4
True
[3, 3, 3, 3]
a b
c d
e f
g h

这让我绝对疯了。如果我进一步分解它,我会发现列表,集合和生成器理解都试图这样做:

[(x,y) for x, y in "a,b".split(",")]

任何人都知道为什么会这样?

3 个答案:

答案 0 :(得分:2)

此代码:

for x, y in "a,b".split(",")

正在寻找两项可迭代的内部 "a,b".split(",")返回的可迭代(列表)。

但是,它找到的只有'a''b'

>>> "a,b".split(",")
['a', 'b']
>>>

由于这两者都只是 one-item iterables(包含一个字符的字符串),因此代码会中断。


考虑到上述情况,请观察在逗号的每一侧添加额外字符时会发生什么:

>>> "ax,by".split(",")
['ax', 'by']
>>> [(x,y) for x, y in "ax,by".split(",")]
[('a', 'x'), ('b', 'y')]
>>>

如您所见,代码现在有效。

这是因为"ax,by".split(",")返回一个包含两项迭代(包含两个字符的字符串)的iterable(列表)。此外,这正是for x, y in正在寻找的内容。


但是,您也可以将最后一部分放在元组中:

>>> ("a,b".split(","),)
(['a', 'b'],)
>>> [(x,y) for x, y in ("a,b".split(","),)]
[('a', 'b')]
>>>

("a,b".split(","),)返回一个包含两项迭代的迭代(元组)(一个包含两个字符串的列表)。再一次,这正是for x, y in正在寻找的东西,因此代码可以正常工作。


考虑到这一切,下面应该解决您的问题:

[(x, y) for line in lines.split() for x, y in (line.split(','),)]

答案 1 :(得分:1)

为什么不呢?

[tuple(l.split(',')) for l in lines ]

l.split(',')每个l只生成两个项目,而不是每个l的两个项目的可迭代项

答案 2 :(得分:0)

为什么不呢:

lines = """
a,b
c,d
e,f
g,h
"""

lines = [line for line in lines.split()]

print(lines)
print(len(lines))
print([len(line) for line in lines])
print(all(',' in line for line in lines))

[l.split(",") for l in lines]