2013-12-07 1 views
3

Я пытался сократить код для this problem, когда столкнулся с проблемой.Как построить вложенное понимание словаря в Python с правильным упорядочением?

В принципе, я пытался понять вложенное словосочетание & был не увенчался успехом. Вот что я пробовал.

dict2 = {key:value for key, value in line.split(":") 
        for line in ["1:One", "2:Two", "4:Four"]} 
print dict2 

Когда я запускаю это, он дает мне

NameError: name 'line' is not defined 

И, когда я полностью изменить for заявления, как этот

dict2 = {key:value for line in ["1:One", "2:Two", "4:Four"] 
        for key, value in line.split(":")} 
print dict2 

Это приводит к

ValueError: need more than 1 value to unpack 

I нужна помощь в рекламе ng структура dictionary (или list) понимание. Примером может служить помощь.

+0

Это на самом деле превосходный вопрос и подчеркивает нечто совершенно неадресация в документе Python. Есть много способов реализовать это плохо. Надеюсь, что это задокументировано, поэтому мы не становимся PERL ... – smci

+0

@smci Python открыт, вы всегда можете отправить патч :) Документы проще кода, так как требуется минимальное тестирование. –

ответ

8

Обратите внимание, что есть лучший способ сделать это без понимания dict; Смотри ниже. Сначала я рассмотрю проблемы с вашим подходом.

Вам необходимо использовать порядок гнездования в понимании. Перечислите свои циклы в том же порядке, в котором они будут находиться, когда вложен регулярный цикл.

Выражение line.split() возвращает последовательность из двух элементов, но каждый из этих элементов равен не кортеж ключа и значения; вместо этого есть только один элемент, повторяющийся. Заверните раскол в кортеже, так что вы едите «последовательность» в (key, value) пунктах будут уступали назначить два результата к двум пунктам:

dict2 = {key:value for line in ["1:One", "2:Two", "4:Four"] 
        for key, value in (line.split(":"),)} 

Это эквивалент:

dict2 = {} 
for line in ["1:One", "2:Two", "4:Four"]: 
    for key, value in (line.split(":"),): 
     dict2[key] = value 

где вложенному петля нужна только потому, что вы не можете сделать:

dict2 = {} 
for line in ["1:One", "2:Two", "4:Four"]: 
    key, value = line.split(":") 
    dict2[key] = value 

Однако в этом случае вместо словаря понимания, вы должны использовать dict() конструктор. Он хочет два-элементные последовательности, упрощая всю операцию:

dict2 = dict(line.split(":") for line in ["1:One", "2:Two", "4:Four"]) 
+0

Я бы предпочел использовать 'dict (el.split (':') для el в the_list)' –

+0

Итак, только 'tuple' позволяет нам присваивать значения нескольким переменным (через распаковку) ?! –

+2

@AshishNitinPatil: У вас есть 'для ключа, значение в ('ключ', 'значение')' здесь, это не работает.Но 'для ключа, значение в (('ключ', 'значение'),)' * does *. –

4

Вы можете сделать это намного проще с dict и generator expression:

>>> lst = ["1:One", "2:Two", "4:Four"] 
>>> dict(x.split(":") for x in lst) 
{'4': 'Four', '1': 'One', '2': 'Two'} 
>>> 
+0

Это на самом деле гораздо более элегантный, чем принятый ответ (tuple-распаковка/переупаковка Олимпийских игр) и должен быть принятым ответом. cc @MartijnPieters – smci

+0

@smci Но это не то, что требует вопрос. Ответ Мартинн прекрасно описывает, что я делаю неправильно, как это должно быть сделано ** и **, как эффективно это делать без понимания понятий. –

+0

@AshishNitinPatil: да, и я самостоятельно приехал сюда, ища то же самое (проблема при заказе/распаковке при вложенном понимании dict). Но, сравнивая подход nested-dict-comp к использованию dict-constructor-take-tuples-of- (key, value), мы ясно видим, что (ключ, значение) -pair-tuple-inside-a-1-tuple для обхода порядка распаковки/заказа является антипаттерн Python, и один настолько плохой и запутанный, что пользователи должны быть предупреждены о его использовании, очень громко и ясно. Как я уже сказал, если мы допустим 33 способа реализовать что-то, а 32 из них субоптимальные и нечитаемые, мы быстро станем PERL. Который следует избегать – smci

Смежные вопросы