Написання диктанту в txt-файл і читання його назад?


115

Я намагаюся написати словник у файл txt. Потім прочитайте значення 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)

У чому проблема з цим кодом?
Блендер

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, тому немає жодного способу, щоб хитра рядок могла зробити щось погано на вашому комп'ютері.

EDIT

Насправді найкращою практикою в 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 VM) або "PyPy" (дійсно класна експериментальна система з оптимізацією коду за часом), не зможуть закрити файл для вас. Це добре ввійти в звичку користуватися with, і я думаю, що це робить код досить легким для розуміння.


dict()очікує словник або список кортежів. Він не буде оцінювати рядок.
Блендер

@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}

5
ви повинні відкрити файл для читання / написання у withвиписці, щоб переконатися, що він закривається після?
ecoe

2
WOW, це так красиво.
zx1986

3
У мене виникли проблеми з використанням цього методу в деяких складних словниках, у яких вкладені задані значення (наприклад d = {"one": {"1" : 1, "a": {"i"}}}). Тому я рекомендую метод соління @ blender, який працює в моєму випадку.
Gürol Canbek

1
Зауважте, що json python переводить клавіші dict у рядки під час виконання json.dump, тому він json.dump({1: 'one'}, file)буде читати назад, як {'1': 'one'}при json.load. Краще використовувати соління, якщо ви не збираєтеся читати збережений файл іншими мовами, ніж Python.
пілінг

Чи є спосіб використовувати щось на зразок json.dumps (dict_x, indent = 4) для форматування способу написання dict у файл, щоб зробити його більш розбірливим? Коли я використовую ваш код, весь диктант записується в один рядок, незалежно від того, наскільки він великий, і він не легко читається.
гертеладрій

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, при читанні друку батогом [ім'я] TypeError: рядкові індекси повинні бути цілими числами, а не str Я думав, що p = Person () визначив це
Radioactive Head

Цей текст відсутній у вашому коді. Перш ніж задавати питання, поясніть, що не так.
Блендер

2
Щоб зберігати об’єкти Python у файлах, використовуйте модуль підбору, якщо це не конфігураційні файли, щоб ви могли редагувати їх людиною - див. Чому турбуватися з файлами python та config?
Пьотр Доброгост

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")

Спершу воно збереже ім’я ключа, а потім усі значення. Зауважте, що в цьому випадку мій дикт містить цілі числа, тому він перетворюється на 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)

Чудовий код, якщо ваші значення не надто довгі. У моєму словнику було кілька довгих рядків, які щойно відрізалися від "..."
Енн,

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')
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.