2013-12-14 3 views
0

Случай использования: у меня длинная строка, разделенная на строки, и каждая строка имеет два элемента, разделенных запятой.Странное поведение распаковки значений при расщеплении строки в Python

В идеале, это должно работать

[(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 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(",")] 

Любое имеет представление о том, почему это происходит?

ответ

2

Этот код:

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

ищет двух пункта итерируемыми, которые внутри итерируемый (список), возвращенный "a,b".split(",").

Однако, все это находит это 'a' и 'b':

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

Поскольку оба они являются лишь один пункт итерируемыми (строки с одного символа), код брейки.


Учитывая вышеизложенное, посмотреть, что происходит, когда дополнительный символ добавляется в каждую сторону от запятой:

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

Как вы можете видеть, код теперь работает.

Это потому, что "ax,by".split(",") возвращает итерируемый (список), который содержит итерации двух элементов (строки с двумя символами). Кроме того, это именно то, что ищет 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(','),)] 
+0

Спасибо за объяснение, почему мои предположения были неправильными. Оценил это :) – thismachinechills

1

Почему бы и нет?

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

l.split(',') производит только две детали для каждого l, а не итератора двух элементов в каждой l

+0

Конечно, я мог бы сделать это, но он побеждает точку если я захотел выполнить операцию над определенными элементами без необходимости разрывать скобки и индексы :) – thismachinechills

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] 
Смежные вопросы