Viết một dict vào tệp txt và đọc lại nó?


115

Tôi đang cố gắng ghi từ điển vào tệp txt. Sau đó, đọc các giá trị dict bằng cách gõ các phím với raw_input. Tôi cảm thấy như tôi chỉ thiếu một bước nhưng tôi đã tìm kiếm từ nãy đến giờ.

Tôi gặp lỗi này

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

Mã của tôi:

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

Có vấn đề gì với mã này?
Máy xay sinh tố

name 'p' is not defined, P phải là một thể hiện của lớp Person
avasal

Câu trả lời:


97

Mã của bạn gần như đúng ! Bạn đúng, bạn chỉ thiếu một bước. Khi bạn đọc trong tệp, bạn đang đọc nó dưới dạng một chuỗi; nhưng bạn muốn chuyển chuỗi trở lại thành từ điển.

Thông báo lỗi bạn thấy là do self.whipmột chuỗi, không phải từ điển.

Đầu tiên tôi đã viết rằng bạn chỉ có thể nạp chuỗi vào dict()nhưng điều đó không hoạt động! Bạn cần phải làm một cái gì đó khác.

Thí dụ

Đây là cách đơn giản nhất: nạp chuỗi vào eval(). Như vậy:

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

Bạn có thể làm điều đó trong một dòng, nhưng tôi nghĩ nó trông lộn xộn theo cách này:

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

Nhưng eval()đôi khi không được khuyến khích. Vấn đề là điều đó eval()sẽ đánh giá bất kỳ chuỗi nào , và nếu ai đó lừa bạn chạy một chuỗi thực sự khó khăn, điều gì đó tồi tệ có thể xảy ra. Trong trường hợp này, bạn chỉ đang chạy eval()trên tệp của riêng mình, vì vậy nó sẽ ổn.

Nhưng vì eval()nó hữu ích, ai đó đã tạo ra một giải pháp thay thế an toàn hơn cho nó. Điều này được gọi literal_evalvà bạn nhận được nó từ một mô-đun Python được gọi ast.

import ast

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

ast.literal_eval() sẽ chỉ đánh giá các chuỗi biến thành các loại Python cơ bản, vì vậy không có cách nào mà một chuỗi phức tạp có thể làm điều gì đó xấu trên máy tính của bạn.

BIÊN TẬP

Trên thực tế, phương pháp hay nhất trong Python là sử dụng một withcâu lệnh để đảm bảo tệp được đóng đúng cách. Viết lại phần trên để sử dụng một withcâu lệnh:

import ast

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

Trong Python phổ biến nhất, được gọi là "CPython", bạn thường không cần withcâu lệnh vì các tính năng "thu gom rác" được tích hợp sẵn sẽ tìm ra rằng bạn đã hoàn thành tệp và sẽ đóng tệp đó cho bạn. Nhưng các triển khai Python khác, như "Jython" (Python cho máy ảo Java) hoặc "PyPy" (một hệ thống thử nghiệm thực sự thú vị với tối ưu hóa mã kịp thời) có thể không tìm ra cách đóng tệp cho bạn. Thật tốt nếu bạn có thói quen sử dụng withvà tôi nghĩ nó làm cho mã khá dễ hiểu.


dict()mong đợi một từ điển hoặc một danh sách các bộ giá trị. Nó sẽ không đánh giá một chuỗi.
Máy xay sinh tố

@Blender Ồ, bạn nói đúng và tôi mệt mỏi. Tôi sẽ chỉnh sửa câu trả lời.
steveha

@Nick: Hãy thử chạy nó trước;)
Máy xay sinh tố

@Blender, cảm ơn bạn đã quan tâm. Và vì tôi đang mệt nên tôi nghĩ rằng tôi sẽ ngừng đăng bài trên StackOverflow trong đêm nay! :-)
steveha

175

Bạn đã thử mô-đun json chưa? Định dạng JSON rất giống với từ điển python. Và con người có thể đọc / ghi được:

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

Mã này kết xuất vào một tệp văn bản

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

Ngoài ra, bạn có thể tải từ tệp JSON:

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

5
bạn có nên mở tệp để đọc / ghi trong một withcâu lệnh để đảm bảo nó sẽ đóng lại sau đó không?
ecoe

2
WOW, điều này thật đẹp.
zx1986

3
Tôi đã gặp sự cố khi sử dụng phương pháp này trên một số từ điển phức tạp có các giá trị đặt lồng nhau (ví dụ d = {"one": {"1" : 1, "a": {"i"}}}:). Do đó, tôi khuyên bạn nên sử dụng phương pháp dưa chua của @ máy xay sinh tố phù hợp với trường hợp của tôi.
Gürol Canbek

1
Lưu ý rằng json của python dịch các phím dict thành chuỗi khi thực hiện json.dump, vì vậy json.dump({1: 'one'}, file)sẽ đọc ngược lại như {'1': 'one'}khi thực hiện json.load. Tốt hơn nên sử dụng pickle nếu bạn không đọc tệp đã lưu bằng các ngôn ngữ khác ngoài Python.
peeol

Có cách nào để sử dụng một cái gì đó như json.dumps (dict_x, indent = 4) để định dạng cách ghi dict vào tệp để làm cho nó dễ đọc hơn không? Khi tôi sử dụng mã của bạn, toàn bộ lệnh được ghi vào một dòng, bất kể nó lớn đến mức nào và con người không dễ đọc được.
herteladrian

70

Để lưu trữ các đối tượng Python trong tệp, hãy sử dụng picklemô-đun:

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

Lưu ý rằng tôi không bao giờ đặt b = a, mà thay vào đó tôi achọn một tệp và sau đó bỏ chọn nó vào b.

Đối với lỗi của bạn:

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

self.whiplà một đối tượng từ điển. deed.txtchứa văn bản, vì vậy khi bạn tải nội dung của deed.txtvào self.whip, self.whipsẽ trở thành biểu diễn chuỗi của chính nó.

Bạn có thể muốn đánh giá chuỗi trở lại thành một đối tượng Python:

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

Chú ý evalâm thanh như thế nào evil. Cố ý đấy. Sử dụng picklemô-đun thay thế.


không có nó mang lại cho tôi lỗi file này "name.py", dòng 24, đọc in roi [name] Lỗi Loại: chuỗi chỉ số phải là số nguyên, không str Tôi nghĩ p = Person () định nghĩa nó
phóng xạ Head

Văn bản đó không có trong mã của bạn. Trước khi đặt câu hỏi, hãy giải thích điều gì sai.
Máy xay sinh tố

2
Để lưu trữ các đối tượng Python trong tệp, hãy sử dụng mô-đun pickle Trừ khi đây là các tệp cấu hình nên bạn muốn con người có thể chỉnh sửa chúng - hãy xem Tại sao phải quan tâm đến tệp python và tệp cấu hình?
Piotr Dobrogost

1
Hoàn hảo. Đây chính xác là những gì tôi cần: để lưu trữ trạng thái cấu trúc python gốc trong một tệp không dành cho người dùng có thể chỉnh sửa.
bahamat

Phương pháp này hoạt động hoàn hảo cho các từ điển phức tạp như tôi đã mô tả trong nhận xét của tôi đối với phương pháp JSON được đề xuất bởi @KFL
Gürol Canbek

8

Tôi đã tạo các hàm của riêng mình hoạt động rất độc đáo:

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

Nó sẽ lưu trữ tên khóa đầu tiên, sau đó là tất cả các giá trị. Lưu ý rằng trong trường hợp này, dict của tôi chứa các số nguyên vì vậy đó là lý do tại sao nó chuyển đổi thành int. Đây rất có thể là phần bạn cần thay đổi cho tình huống của mình.

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)

Mã tuyệt vời nếu giá trị của bạn không quá dài. Từ điển của tôi bao gồm nhiều chuỗi dài vừa bị cắt bằng '...'
Anne

7

Xin chào, có một cách để ghi và đọc từ điển vào tệp, bạn có thể chuyển từ điển của mình sang định dạng JSON và đọc và ghi nhanh chóng chỉ cần thực hiện điều này:

Để viết ngày của bạn:

 import json

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

và để đọc dữ liệu của bạn:

 import json

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

6

Bạn có thể lặp lại cặp khóa-giá trị và ghi nó vào tệp

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')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.