Чтение из файла с использованием понимания dict

Мне регулярно нужно читать данные из файлов (обычно значения, разделенные табуляцией) и преобразовывать их в словари. Обычно мне просто нужно сопоставить один из столбцов с другим, но также может быть некоторая обработка значений (например, удаление пробелов). Я пытался придумать шаблон понимания dict, чтобы сделать это, но я продолжаю сталкиваться с небольшими неприятностями, которые мешают мне последовательно реализовать его наиболее кратким и понятным способом. И у меня есть ощущение, что, вероятно, есть лучший способ.

Итак, вот (некоторые) способы, которые я пробовал, и где они пошли не так:


with open(path) as f:
    return {line.split("\t")[0].strip(): line.split("\t")[1].strip()
            for line in f}

Это то, чем я часто пользуюсь. Это позволяет мне изменять ключ и значение на месте и будет работать с любым из столбцов (например, если я хочу сопоставить значения из третьего столбца с первым). Очевидной проблемой является дублирование части line.split(). Есть ли способ привязать line.split("\t") к временной переменной или распаковать значения непосредственно в переменные?


with open(path) as f:
    return dict(line.split("\t")[:2] for line in f)

Я только что придумал это. Это хорошо работает для этого простого случая (просто сопоставление первого столбца со вторым без какой-либо обработки), но не распространяется на другие случаи. Дополнительную обработку выполнить сложно, а используемые столбцы должны быть смежными. Это также не строгое понимание dict, и его нельзя превратить в одно, потому что оно использует срезы.


d = dict()
for line in open(path):
    d.update({line.split("\t")[0]: line.split("\t")[1]})
return d

Конечно, я мог бы просто сначала создать словарь, а затем обновлять каждую строку. Но теперь я должен создать dict и вернуть его отдельно, а дублирование кода все еще существует.


Я также поиграл с вложенными пониманиями dict и распаковал разделенную строку в переменные, но столкнулся с другими проблемами.


person Sebastian Hofer    schedule 05.02.2016    source источник
comment
Вы пытаетесь оптимизировать что-то, что, вероятно, связано с вводом-выводом, поэтому все, что вы делаете, кроме создания словарей с такой скоростью или с наименьшим объемом кода, скорее всего, не будет иметь большого значения.   -  person martineau    schedule 05.02.2016


Ответы (2)


Вы можете сделать это, поместив что-нибудь вокруг вашего f:

def tabsplit(file_object):
    for line in file_object:
        yield line.split("\t")

А потом позже:

with open(path) as f:
    return {left.strip(): right.strip() for left, right, *rest in tabsplit(f)}
person L3viathan    schedule 05.02.2016
comment
Интересно, я не пробовал использовать генераторы каким-либо образом... Однако именно здесь вступают в игру проблемы с распаковкой, на которые я намекал ранее. Входные файлы могут содержать разное количество вкладок — например, могут быть конечные значения, принадлежащие последнему столбцу. Затем эти файлы выдают ошибку ValueError, которую я не знаю, как обрабатывать при понимании dict. Файлы также обычно содержат другие столбцы, которые не должны быть в словаре - возможно игнорирование их путем распаковки в _, _, ..., но я тоже не нахожу это очень элегантным. - person Sebastian Hofer; 05.02.2016
comment
Итак, вы хотите игнорировать все столбцы, кроме первых двух? Смотрите мое редактирование, чтобы выбросить *rest. - person L3viathan; 05.02.2016

Не уверен, почему создание словаря сначала не сработает

result = {}
with open(path) as f:
    for line in f:
        columns = line.split("\t")
        key = columns[0] # first item is the key right?
        result[key] = columns[1]
person Ramast    schedule 05.02.2016
comment
Конечно, это работает, но я пытаюсь сделать это как можно более кратким. Вот почему мне не нравятся отдельные шаги объявления и возврата, даже если это было бы одним из самых читаемых решений. - person Sebastian Hofer; 05.02.2016
comment
@Sebastian: Краткость не всегда == лучше. Удобочитаемость и ремонтопригодность имеют большое значение, а эффективность часто не имеет значения... например, в 97% случаев. См. Когда оптимизировать. - person martineau; 05.02.2016
comment
@martineau Я знаю, именно поэтому я задаю этот вопрос. Поиск шаблона кода, который я всегда могу использовать для этого, позволил бы мне использовать его последовательно, тем самым повышая удобство сопровождения и понятность в долгосрочной перспективе. И если я смогу найти шаблон с меньшим количеством строк, я, вероятно, предпочту это просто потому, что он меньше прокручивается - я обычно работаю в блокноте IPython, и дополнительные строки добавляются довольно быстро... - person Sebastian Hofer; 05.02.2016
comment
@Sebastian: Оба этих ответа делают это достаточно хорошо. Чтобы свести к минимуму количество строк, сделайте ее полезной функцией... аналогично тому, что сделал L3viathan, но на более высоком уровне. Разделение задачи на части часто может быть полезным по ряду причин. - person martineau; 05.02.2016