Menulis dikt ke file txt dan membacanya kembali?

115

Saya mencoba menulis kamus ke file txt. Kemudian baca nilai dict dengan mengetikkan kunci dengan raw_input. Saya merasa seperti saya hanya melewatkan satu langkah tetapi saya telah mencari beberapa saat sekarang.

Saya mendapatkan kesalahan ini

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

Kode saya:

#!/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)
Kepala Radioaktif
sumber
Apa masalah dengan kode ini?
Blender
name 'p' is not defined, p harus merupakan turunan dari kelas Person
avasal

Jawaban:

97

Kode Anda hampir benar ! Anda benar, Anda hanya melewatkan satu langkah. Saat Anda membaca di file, Anda membacanya sebagai string; tetapi Anda ingin mengubah string itu kembali menjadi kamus.

Pesan kesalahan yang Anda lihat adalah karena self.whipmerupakan string, bukan kamus.

Saya pertama kali menulis bahwa Anda bisa memberi makan string ke dalam dict()tetapi itu tidak berhasil! Anda perlu melakukan sesuatu yang lain.

Contoh

Inilah cara termudah: masukkan string ke dalam eval(). Seperti:

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

Anda dapat melakukannya dalam satu baris, tetapi menurut saya akan terlihat berantakan seperti ini:

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

Namun eval()terkadang tidak disarankan. Masalahnya adalah itu eval()akan mengevaluasi string apa pun , dan jika seseorang menipu Anda untuk menjalankan string yang sangat rumit, sesuatu yang buruk mungkin terjadi. Dalam hal ini, Anda hanya menjalankan eval()file Anda sendiri, jadi tidak masalah.

Tetapi karena eval()bermanfaat, seseorang membuat alternatif yang lebih aman. Ini disebut literal_evaldan Anda mendapatkannya dari modul Python yang disebut ast.

import ast

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

ast.literal_eval() hanya akan mengevaluasi string yang berubah menjadi jenis Python dasar, jadi tidak mungkin string yang rumit dapat melakukan sesuatu yang buruk di komputer Anda.

EDIT

Sebenarnya, praktik terbaik dalam Python adalah menggunakan withpernyataan untuk memastikan file ditutup dengan benar. Menulis ulang hal di atas untuk menggunakan withpernyataan:

import ast

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

Di Python paling populer, yang dikenal sebagai "CPython", Anda biasanya tidak memerlukan withpernyataan karena fitur "pengumpulan sampah" bawaan akan mengetahui bahwa Anda telah selesai dengan file tersebut dan akan menutupnya untuk Anda. Tetapi implementasi Python lainnya, seperti "Jython" (Python untuk Java VM) atau "PyPy" (sistem eksperimental yang sangat keren dengan pengoptimalan kode just-in-time) mungkin tidak berhasil menutup file untuk Anda. Itu bagus untuk membiasakan diri menggunakan with, dan menurut saya itu membuat kode cukup mudah dimengerti.

steveha.dll
sumber
dict()mengharapkan kamus atau daftar tupel. Itu tidak akan mengevaluasi string.
Blender
@ Blender Oh, kamu benar dan aku lelah. Saya akan mengedit jawabannya.
steveha
@ Nick: Coba jalankan dulu;)
Blender
@ Blender, terima kasih atas perhatiannya. Dan karena saya lelah, saya rasa saya akan berhenti memposting di StackOverflow untuk malam ini! :-)
steveha
175

Sudahkah Anda mencoba modul json ? Format JSON sangat mirip dengan kamus python. Dan itu bisa dibaca / ditulis manusia:

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

Kode ini dibuang ke file teks

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

Anda juga dapat memuat dari file JSON:

>>> d2 = json.load(open("text.txt"))
>>> print d2
{u'two': 2, u'one': 1}
KFL
sumber
5
haruskah Anda membuka file untuk membaca / menulis dalam withpernyataan untuk memastikannya ditutup setelahnya?
ecoe
2
WOW, ini sangat indah.
zx1986
3
Saya mengalami masalah dalam menggunakan metode ini pada beberapa kamus kompleks seperti memiliki nilai set bersarang (misalnya d = {"one": {"1" : 1, "a": {"i"}}}). Oleh karena itu, saya merekomendasikan metode acar @ blender yang berfungsi dalam kasus saya.
Gürol Canbek
1
Perhatikan bahwa json python menerjemahkan kunci dict menjadi string saat melakukan json.dump, jadi json.dump({1: 'one'}, file)akan membaca kembali seperti {'1': 'one'}saat melakukan json.load. Lebih baik menggunakan acar jika Anda tidak akan membaca file yang disimpan menggunakan bahasa lain selain Python.
peeol
Apakah ada cara untuk menggunakan sesuatu seperti json.dumps (dict_x, indent = 4) untuk memformat cara dict ditulis ke file agar lebih terbaca? Ketika saya menggunakan kode Anda, seluruh dict ditulis ke satu baris, tidak peduli seberapa besar itu, dan itu tidak mudah dibaca manusia.
herteladrian
70

Untuk menyimpan objek Python dalam file, gunakan picklemodul:

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

Perhatikan bahwa saya tidak pernah mengatur b = a, tetapi malah menjadi acar ake file dan kemudian membukanya menjadi b.

Adapun kesalahan Anda:

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

self.whipadalah objek kamus. deed.txtberisi teks, jadi saat Anda memuat konten deed.txtke self.whip, self.whipmenjadi representasi string itu sendiri.

Anda mungkin ingin mengevaluasi string kembali menjadi objek Python:

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

Perhatikan bagaimana evalsuaranya evil. Itu disengaja. Gunakan picklemodul sebagai gantinya.

Blender
sumber
tidak ada yang memberi saya kesalahan ini File "name.py", baris 24, dalam membaca print whip [name] TypeError: indeks string harus bilangan bulat, bukan str Saya pikir p = Person () mendefinisikannya
Radioactive Head
Teks itu tidak ada dalam kode Anda. Sebelum mengajukan pertanyaan, jelaskan apa yang salah.
Blender
2
Untuk menyimpan objek Python dalam file, gunakan modul acar Kecuali ini adalah file konfigurasi jadi Anda ingin mereka dapat diedit oleh manusia - lihat Mengapa repot-repot dengan file python dan config?
Piotr Dobrogost
1
Sempurna. Inilah yang saya butuhkan: untuk menyimpan status struktur python asli dalam file yang tidak dimaksudkan untuk dapat diedit pengguna.
bahamat
Metode ini bekerja dengan sempurna untuk kamus yang kompleks seperti yang saya jelaskan dalam komentar saya untuk metode JSON yang disarankan oleh @KFL
Gürol Canbek
8

Saya membuat fungsi saya sendiri yang bekerja dengan sangat baik:

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

Ini akan menyimpan nama kunci terlebih dahulu, diikuti oleh semua nilai. Perhatikan bahwa dalam kasus ini dict saya berisi bilangan bulat jadi itulah mengapa itu diubah menjadi int. Kemungkinan besar ini adalah bagian yang perlu Anda ubah untuk situasi Anda.

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
sumber
Kode bagus jika nilai Anda tidak terlalu panjang. Kamus saya menyertakan beberapa string panjang yang baru saja dipotong dengan '...'
Anne
7

Hai ada cara untuk menulis dan membaca kamus ke file Anda dapat mengubah kamus Anda ke format JSON dan membaca dan menulis dengan cepat lakukan ini:

Untuk menulis tanggal Anda:

 import json

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

dan untuk membaca data Anda:

 import json

 f = open('destFile.txt', 'r')
 your_dictionary = json.loads(f.read())
Manouchehr Rasouli
sumber
6

Anda dapat melakukan iterasi melalui key-value pair dan menuliskannya ke dalam 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')
Aravind Krishnakumar
sumber