Scrivere un dict in un file txt e leggerlo di nuovo?


115

Sto cercando di scrivere un dizionario su un file txt. Quindi leggi i valori di dict digitando i tasti con raw_input. Mi sento come se mi mancasse solo un passaggio, ma lo stavo cercando da un po 'di tempo.

Ottengo questo errore

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

Il mio codice:

#!/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)

Qual è il problema con questo codice?
Blender

name 'p' is not defined, p dovrebbe essere un'istanza della classe Persona
avasal

Risposte:


97

Il tuo codice è quasi corretto ! Hai ragione, ti manca solo un passaggio. Quando leggi nel file, lo stai leggendo come una stringa; ma vuoi trasformare di nuovo la stringa in un dizionario.

Il messaggio di errore che hai visualizzato era perché self.whipera una stringa, non un dizionario.

Ho scritto per la prima volta che potresti semplicemente inserire la stringa dict()ma non funziona! Devi fare qualcos'altro.

Esempio

Ecco il modo più semplice: inserire la stringa in eval(). Così:

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

Puoi farlo in una riga, ma penso che sembri disordinato in questo modo:

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

Ma a eval()volte non è raccomandato. Il problema è che eval()valuterà qualsiasi stringa e se qualcuno ti ha indotto a eseguire una stringa davvero complicata, potrebbe accadere qualcosa di brutto. In questo caso, stai solo eseguendo eval()il tuo file, quindi dovrebbe essere a posto.

Ma poiché eval()è utile, qualcuno ne ha fatto un'alternativa più sicura. Questo è chiamato literal_evale lo ottieni da un modulo Python chiamato ast.

import ast

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

ast.literal_eval() valuterà solo le stringhe che si trasformano nei tipi di Python di base, quindi non c'è modo che una stringa complicata possa fare qualcosa di male sul tuo computer.

MODIFICARE

In realtà, la migliore pratica in Python consiste nell'usare withun'istruzione per assicurarsi che il file venga chiuso correttamente. Riscrittura di quanto sopra per utilizzare una withdichiarazione:

import ast

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

Nel più popolare Python, noto come "CPython", di solito non hai bisogno withdell'istruzione poiché le funzionalità incorporate di "garbage collection" scopriranno che hai finito con il file e lo chiuderanno per te. Ma altre implementazioni di Python, come "Jython" (Python per Java VM) o "PyPy" (un sistema sperimentale davvero interessante con ottimizzazione del codice just-in-time) potrebbero non riuscire a chiudere il file per te. È bello prendere l'abitudine di usare withe penso che renda il codice abbastanza facile da capire.


dict()si aspetta un dizionario o un elenco di tuple. Non valuterà una stringa.
Blender

@ Blender Oh, hai ragione e sono stanco. Modificherò la risposta.
steveha

@ Nick: prova a eseguirlo prima;)
Blender

@ Blender, grazie per l'avvertimento. E poiché sono stanco, penso che smetterò di pubblicare su StackOverflow per la notte! :-)
steveha

175

Hai provato il modulo json ? Il formato JSON è molto simile al dizionario Python. Ed è leggibile / scrivibile dall'uomo:

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

Questo codice esegue il dump in un file di testo

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

Inoltre puoi caricare da un file JSON:

>>> d2 = json.load(open("text.txt"))
>>> print d2
{u'two': 2, u'one': 1}

5
dovresti aprire il file in lettura / scrittura in withun'istruzione per assicurarti che si chiuda dopo?
ecoe

2
WOW, è così bello.
zx1986

3
Ho riscontrato problemi nell'utilizzo di questo metodo su alcuni dizionari complessi come quelli con valori impostati annidati (ad esempio d = {"one": {"1" : 1, "a": {"i"}}}). Pertanto, consiglio il metodo pickle di @ blender che funziona nel mio caso.
Gürol Canbek

1
Si noti che il json di python traduce le chiavi di dict in stringhe quando si esegue json.dump, quindi json.dump({1: 'one'}, file)verrà letto come {'1': 'one'}quando si esegue json.load. Meglio usare pickle se non hai intenzione di leggere il file salvato utilizzando linguaggi diversi da Python.
peeol

C'è un modo per usare qualcosa come json.dumps (dict_x, indent = 4) per formattare il modo in cui il dict viene scritto nel file per renderlo più leggibile? Quando uso il tuo codice, l'intero dict viene scritto su una riga, non importa quanto grande sia, e non è facilmente leggibile dall'uomo.
herteladrian

70

Per memorizzare oggetti Python in file, usa il picklemodulo:

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

Si noti che non ho mai impostato b = a, ma invece ho selezionato aun file e poi lo ho rimosso in b.

Per quanto riguarda il tuo errore:

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

self.whipera un oggetto dizionario. deed.txtcontiene testo, quindi quando carichi il contenuto di deed.txtin self.whip, self.whipdiventa la rappresentazione di stringa di se stesso.

Probabilmente vorresti rivalutare la stringa in un oggetto Python:

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

Nota come evalsuona evil. È intenzionale. Usa pickleinvece il modulo.


no mi dà questo errore File "name.py", riga 24, in lettura print whip [nome] TypeError: gli indici delle stringhe devono essere interi, non str Pensavo che p = Person () lo definisse
Radioactive Head

Quel testo non è nel tuo codice. Prima di fare una domanda, spiega cosa c'è che non va.
Blender

2
Per memorizzare oggetti Python nei file, usa il modulo pickle A meno che questi non siano file di configurazione, quindi vuoi che siano modificabili dall'uomo - vedi Perché perdere tempo con i file Python e di configurazione?
Piotr Dobrogost

1
Perfetto. Questo è esattamente ciò di cui ho bisogno: memorizzare lo stato della struttura nativa di Python in un file che non deve essere modificabile dall'utente.
bahamat

Questo metodo funziona perfettamente per dizionari complessi come ho descritto nel mio commento per il metodo JSON suggerito da @KFL
Gürol Canbek

8

Ho creato le mie funzioni che funzionano davvero bene:

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

Memorizzerà prima il nome chiave, seguito da tutti i valori. Nota che in questo caso il mio dict contiene numeri interi, quindi è per questo che converte in int. Questa è molto probabilmente la parte che devi cambiare per la tua situazione.

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)

Ottimo codice se i tuoi valori non sono troppo lunghi. Il mio dizionario includeva più stringhe lunghe che sono state appena interrotte con "..."
Anne

7

Ciao, c'è un modo per scrivere e leggere il dizionario su file, puoi trasformare il tuo dizionario in formato JSON e leggere e scrivere velocemente, basta fare questo:

Per scrivere la tua data:

 import json

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

e per leggere i tuoi dati:

 import json

 f = open('destFile.txt', 'r')
 your_dictionary = json.loads(f.read())

6

Puoi scorrere la coppia chiave-valore e scriverla nel file

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')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.