Записать диктовку в текстовый файл и прочитать его?

115

Пытаюсь записать словарь в текстовый файл. Затем прочтите значения dict, нажав клавиши с помощью raw_input. Я чувствую, что просто упускаю один шаг, но я уже давно искал.

Я получаю эту ошибку

File "name.py", line 24, in reading
    print whip[name]
TypeError: string indices must be integers, not str

Мой код:

#!/usr/bin/env python
from sys import exit

class Person(object):
    def __init__(self):
        self.name = ""
        self.address = ""
        self.phone = ""
        self.age = ""
        self.whip = {}

    def writing(self):
        self.whip[p.name] = p.age, p.address, p.phone
        target = open('deed.txt', 'a')
        target.write(str(self.whip))
        print self.whip

    def reading(self):
        self.whip = open('deed.txt', 'r').read()
        name = raw_input("> ")
        if name in self.whip:
            print self.whip[name]

p = Person()

while True:
    print "Type:\n\t*read to read data base\n\t*write to write to data base\n\t*exit to exit"
    action = raw_input("\n> ")
    if "write" in action:
        p.name = raw_input("Name?\n> ")
        p.phone = raw_input("Phone Number?\n> ")
        p.age = raw_input("Age?\n> ")
        p.address = raw_input("Address?\n>")
        p.writing()
    elif "read" in action:
        p.reading()
    elif "exit" in action:
        exit(0)
Радиоактивная голова
источник
В чем проблема с этим кодом?
Blender
name 'p' is not defined, p должен быть экземпляром класса Person
avasal

Ответы:

97

Ваш код почти правильный ! Вы правы, вам просто не хватает одного шага. Когда вы читаете файл, вы читаете его как строку; но вы хотите превратить строку обратно в словарь.

Вы увидели сообщение об ошибке, потому что self.whipэто строка, а не словарь.

Сначала я написал, что можно просто ввести строку, dict()но это не работает! Вам нужно заняться чем-то другим.

пример

Вот самый простой способ: вставить строку в eval(). Вот так:

def reading(self):
    s = open('deed.txt', 'r').read()
    self.whip = eval(s)

Вы можете сделать это одной строкой, но я думаю, что это выглядит неаккуратно:

def reading(self):
    self.whip = eval(open('deed.txt', 'r').read())

Но eval()иногда не рекомендуется. Проблема в том, что eval()будет оцениваться любая строка, и если кто-то обманом заставил вас запустить действительно сложную строку, может случиться что-то плохое. В этом случае вы просто запускаете eval()свой собственный файл, так что все должно быть в порядке.

Но поскольку eval()это полезно, кто-то сделал ему альтернативу, которая безопаснее. Это называется, literal_evalи вы получаете его из модуля Python с именем ast.

import ast

def reading(self):
    s = open('deed.txt', 'r').read()
    self.whip = ast.literal_eval(s)

ast.literal_eval() будет оценивать только те строки, которые превращаются в базовые типы Python, поэтому хитрая строка не может сделать что-то плохое на вашем компьютере.

РЕДАКТИРОВАТЬ

На самом деле, лучшая практика в Python - использовать withоператор, чтобы убедиться, что файл правильно закрыт. Переписываем приведенное выше, чтобы использовать withоператор:

import ast

def reading(self):
    with open('deed.txt', 'r') as f:
        s = f.read()
        self.whip = ast.literal_eval(s)

В наиболее популярном Python, известном как «CPython», этот withоператор обычно не нужен, поскольку встроенные функции «сборки мусора» определят, что вы закончили работу с файлом, и закроют его за вас. Но другие реализации Python, такие как Jython (Python для виртуальной машины Java) или PyPy (действительно крутая экспериментальная система с своевременной оптимизацией кода), могут не решить, как закрыть файл для вас. Привыкнуть к использованию - это хорошо with, и я думаю, это упрощает понимание кода.

steveha
источник
dict()ожидает словарь или список кортежей. Он не будет оценивать строку.
Blender
@Blender О, ты прав, и я устал. Отредактирую ответ.
Steveha
@Nick: Попробуй сначала запустить;)
Blender
@Blender, спасибо за предупреждение. И поскольку я устал, думаю, что перестану публиковать сообщения на StackOverflow на ночь! :-)
steveha
175

Вы пробовали модуль json ? Формат JSON очень похож на словарь Python. И он доступен для чтения / записи:

>>> import json
>>> d = {"one":1, "two":2}
>>> json.dump(d, open("text.txt",'w'))

Этот код выгружается в текстовый файл

$ cat text.txt 
{"two": 2, "one": 1}

Также вы можете загрузить из файла JSON:

>>> d2 = json.load(open("text.txt"))
>>> print d2
{u'two': 2, u'one': 1}
KFL
источник
5
следует ли открывать файл для чтения / записи в withоператоре, чтобы гарантировать его закрытие после?
ecoe
2
Вау, это так красиво.
zx1986
3
У меня возникли проблемы с использованием этого метода в некоторых сложных словарях, таких как вложенные заданные значения (например d = {"one": {"1" : 1, "a": {"i"}}}). Поэтому я рекомендую метод pickle @blender, который работает в моем случае.
Gürol Canbek 02
1
Обратите внимание, что json python переводит ключи dict в строки при выполнении json.dump, поэтому json.dump({1: 'one'}, file)будет считываться, как {'1': 'one'}при выполнении json.load. Лучше использовать pickle, если вы не собираетесь читать сохраненный файл на других языках, кроме Python.
peeol
Есть ли способ использовать что-то вроде json.dumps (dict_x, indent = 4) для форматирования способа записи dict в файл, чтобы сделать его более разборчивым? Когда я использую ваш код, весь dict записывается в одну строку, независимо от ее размера, и это не легко читается человеком.
herteladrian
70

Для хранения объектов Python в файлах используйте pickleмодуль:

import pickle

a = {
  'a': 1,
  'b': 2
}

with open('file.txt', 'wb') as handle:
  pickle.dump(a, handle)

with open('file.txt', 'rb') as handle:
  b = pickle.loads(handle.read())

print a == b # True

Обратите внимание, что я никогда не устанавливал b = a, а вместо aэтого добавлял в файл, а затем распаковывал его вb .

Что касается вашей ошибки:

self.whip = open('deed.txt', 'r').read()

self.whipбыл объектом словаря. deed.txtсодержит текст, поэтому, когда вы загружаете содержимое deed.txtв self.whip, self.whipстановится строковым представлением самого себя.

Вероятно, вы захотите оценить строку обратно в объект Python:

self.whip = eval(open('deed.txt', 'r').read())

Обратите внимание, как evalзвучит evil. Это сделано намеренно. pickleВместо этого используйте модуль.

Блендер
источник
нет, это дает мне эту ошибку. Файл "name.py", строка 24, при чтении print whip [name] TypeError: строковые индексы должны быть целыми числами, а не str. Я думал, что p = Person () определил это
Radioactive Head
Этого текста нет в вашем коде. Прежде чем задать вопрос, объясните, в чем дело.
Blender
2
Чтобы хранить объекты Python в файлах, используйте модуль pickle. Если это не файлы конфигурации, поэтому вы хотите, чтобы они были доступны для редактирования человеком - см. Зачем беспокоиться о файлах python и config?
Piotr Dobrogost
1
Отлично. Это именно то, что мне нужно: хранить собственное состояние структуры Python в файле, который не предназначен для редактирования пользователем.
bahamat
Этот метод отлично работает со сложными словарями, как я описал в моем комментарии к методу JSON, предложенному @KFL
Gürol Canbek
8

Я создал свои собственные функции, которые действительно прекрасно работают:

def writeDict(dict, filename, sep):
    with open(filename, "a") as f:
        for i in dict.keys():            
            f.write(i + " " + sep.join([str(x) for x in dict[i]]) + "\n")

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

def readDict(filename, sep):
    with open(filename, "r") as f:
        dict = {}
        for line in f:
            values = line.split(sep)
            dict[values[0]] = {int(x) for x in values[1:len(values)]}
        return(dict)
PascalVKooten
источник
Отличный код, если ваши значения не слишком длинные. В моем словаре было несколько длинных строк, которые только что обрезались с помощью '...'
Энн
7

Привет, есть способ написать и прочитать словарь в файл, вы можете превратить свой словарь в формат JSON и быстро читать и писать, просто сделайте это:

Чтобы написать дату:

 import json

 your_dictionary = {"some_date" : "date"}
 f = open('destFile.txt', 'w+')
 f.write(json.dumps(your_dictionary))

и читать ваши данные:

 import json

 f = open('destFile.txt', 'r')
 your_dictionary = json.loads(f.read())
Манучехр Расули
источник
6

Вы можете перебирать пару ключ-значение и записывать ее в файл

pair = {'name': name,'location': location}
with open('F:\\twitter.json', 'a') as f:
     f.writelines('{}:{}'.format(k,v) for k, v in pair.items())
     f.write('\n')
Аравинд Кришнакумар
источник