Piszesz dyktando do pliku txt i czytasz go z powrotem?


115

Próbuję napisać słownik do pliku txt. Następnie przeczytaj wartości dict, wpisując klucze za pomocą raw_input. Czuję, że przegapiłem jeden krok, ale szukałem już od jakiegoś czasu.

Otrzymuję ten błąd

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

Mój kod:

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

Jaki jest problem z tym kodem?
— Blender,

name 'p' is not defined, p powinno być instancją klasy Person
— avasal

Odpowiedzi:


97

Twój kod jest prawie poprawny ! Masz rację, brakuje Ci tylko jednego kroku. Kiedy czytasz plik, czytasz go jako ciąg; ale chcesz przekształcić ciąg z powrotem w słownik.

Wyświetlony komunikat o błędzie brzmiał, ponieważ self.whipbył to ciąg znaków, a nie słownik.

Najpierw napisałem, że możesz po prostu wprowadzić ciąg, dict()ale to nie działa! Musisz zrobić coś innego.

Przykład

Oto najprostszy sposób: wprowadź ciąg do eval(). Tak jak to:

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

Możesz to zrobić w jednej linii, ale myślę, że wygląda to niechlujnie w ten sposób:

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

Ale eval()czasami nie jest zalecane. Problem polega na tym, eval()że oceni każdy ciąg, a jeśli ktoś oszuka cię do uruchomienia naprawdę trudnego ciągu, może się zdarzyć coś złego. W takim przypadku po prostu uruchamiasz eval()swój własny plik, więc powinno być w porządku.

Ale ponieważ eval()jest przydatny, ktoś stworzył dla niego alternatywę, która jest bezpieczniejsza. Nazywa się to literal_evali uzyskujesz to z modułu Pythona o nazwie ast.

import ast

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

ast.literal_eval() oceni tylko łańcuchy, które zamieniają się w podstawowe typy Pythona, więc nie ma możliwości, aby skomplikowany ciąg mógł zrobić coś złego na twoim komputerze.

EDYTOWAĆ

Właściwie najlepszą praktyką w Pythonie jest użycie withinstrukcji, aby upewnić się, że plik zostanie poprawnie zamknięty. Przepisanie powyższego na withoświadczenie:

import ast

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

W najpopularniejszym Pythonie, znanym jako „CPython”, zwykle nie potrzebujesz withinstrukcji, ponieważ wbudowane funkcje „usuwania elementów bezużytecznych” zorientują się, że skończyłeś z plikiem i zamkną go za Ciebie. Ale inne implementacje Pythona, takie jak „Jython” (Python dla maszyny wirtualnej Java) lub „PyPy” (naprawdę fajny system eksperymentalny z optymalizacją kodu w trybie just-in-time) mogą nie zamknąć pliku za Ciebie. Dobrze jest przyzwyczaić się do używania withi myślę, że dzięki temu kod jest łatwy do zrozumienia.


dict()oczekuje słownika lub listy krotek. Nie oceni ciągu.
— Blender,

@Blender Och, masz rację i jestem zmęczony. Zmienię odpowiedź.
— steveha

@Nick: Spróbuj najpierw uruchomić;)
— Blender,

@Blender, dziękuję za ostrzeżenie. A ponieważ jestem zmęczony, myślę, że przestanę pisać na StackOverflow na noc! :-)
— steveha

175

Czy próbowałeś już modułu JSON ? Format JSON jest bardzo podobny do słownika Pythona. I jest czytelny / zapisywalny dla człowieka:

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

Ten kod zrzuca do pliku tekstowego

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

Możesz także załadować z pliku JSON:

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

5
czy powinieneś otworzyć plik do odczytu / zapisu w withoświadczeniu, aby upewnić się, że zostanie zamknięty po?
— ecoe

2
WOW, to jest takie piękne.
— zx1986

3
Doświadczyłem problemów z użyciem tej metody w przypadku niektórych złożonych słowników, takich jak posiadanie zagnieżdżonych wartości zadanych (np d = {"one": {"1" : 1, "a": {"i"}}}.). Dlatego polecam metodę marynowania @ blendera, która działa w moim przypadku.
— Gürol Canbek

1
Zwróć uwagę, że json języka Python tłumaczy klucze dyktowania na ciągi znaków podczas wykonywania json.dump, więc json.dump({1: 'one'}, file)czyta z powrotem tak, jak {'1': 'one'}podczas wykonywania json.load. Lepiej użyć pikle, jeśli nie zamierzasz czytać zapisanego pliku w innych językach niż Python.
— peeol

Czy istnieje sposób na użycie czegoś takiego jak json.dumps (dict_x, indent = 4), aby sformatować sposób, w jaki dict jest zapisywany w pliku, aby był bardziej czytelny? Kiedy używam twojego kodu, cały dykt jest zapisywany w jednej linii, bez względu na to, jak duży jest i nie jest łatwy do odczytania przez człowieka.
— herteladrian

70

Aby przechowywać obiekty Pythona w plikach, użyj picklemodułu:

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

Zauważ, że nigdy nie ustawiłem b = a, ale zamiast tego wytrawiłem ado pliku, a następnie rozpakowałem go b.

Co do twojego błędu:

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

self.whipbył obiektem słownikowym. deed.txtzawiera tekst, więc po załadowaniu zawartości deed.txtdo self.whip, self.whipstaje się ciągową reprezentacją samego siebie.

Prawdopodobnie chciałbyś przeliczyć ciąg z powrotem na obiekt Pythona:

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

Zwróć uwagę, jak evalbrzmi evil. To jest zamierzone. pickleZamiast tego użyj modułu.


nie, to daje mi ten błąd Plik "name.py", wiersz 24, w czytaniu print whip [nazwa] TypeError: indeksy stringów muszą być liczbami całkowitymi, a nie str. Myślałem, że p = Person () zdefiniował to
— Radioactive Head

Tego tekstu nie ma w Twoim kodzie. Zanim zadasz pytanie, wyjaśnij, co się stało.
— Blender,

2
Aby przechowywać obiekty Pythona w plikach, użyj modułu pickle. Jeśli nie są to pliki konfiguracyjne, więc chcesz, aby były edytowalne przez człowieka - zobacz Po co zawracać sobie głowę pythonem i plikami konfiguracyjnymi?
— Piotr Dobrogost

1
Idealny. Właśnie tego potrzebuję: do przechowywania stanu struktury natywnego języka Python w pliku, który nie jest przeznaczony do edycji przez użytkownika.
— Bahamat

Ta metoda działa doskonale w przypadku złożonych słowników, jak opisałem w moim komentarzu do metody JSON zasugerowanej przez @KFL
— Gürol Canbek

8

Stworzyłem własne funkcje, które działają naprawdę fajnie:

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

Najpierw zapisze nazwę klucza, a po niej wszystkie wartości. Zauważ, że w tym przypadku moja dict zawiera liczby całkowite, dlatego jest konwertowana na int. Najprawdopodobniej jest to część, którą musisz zmienić w swojej sytuacji.

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)

Świetny kod, jeśli twoje wartości nie są zbyt długie. Mój słownik zawierał wiele długich ciągów, które właśnie zostały odcięte przez „...”
— Anne

7

Cześć, jest sposób na zapisanie i odczytanie słownika do pliku, w którym możesz zamienić słownik na format JSON oraz szybko czytać i pisać, po prostu zrób to:

Aby napisać datę:

 import json

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

i odczytać Twoje dane:

 import json

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

6

Możesz iterować przez parę klucz-wartość i zapisać ją do pliku

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')
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.