Menyimpan dan memuat benda dan menggunakan acar

114

Saya mencoba untuk menyimpan dan memuat objek menggunakan picklemodul.
Pertama saya mendeklarasikan objek saya:

>>> class Fruits:pass
...
>>> banana = Fruits()

>>> banana.color = 'yellow'
>>> banana.value = 30

Setelah itu saya membuka file bernama 'Fruits.obj' (sebelumnya saya membuat file .txt baru dan saya mengganti nama 'Fruits.obj'):

>>> import pickle
>>> filehandler = open(b"Fruits.obj","wb")
>>> pickle.dump(banana,filehandler)

Setelah melakukan ini saya menutup sesi saya dan saya memulai yang baru dan saya meletakkan sesi berikutnya (mencoba mengakses ke objek yang seharusnya disimpan):

file = open("Fruits.obj",'r')
object_file = pickle.load(file)

Tapi saya punya pesan ini:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
ValueError: read() from the underlying stream did notreturn bytes

Saya tidak tahu harus berbuat apa karena saya tidak mengerti pesan ini. Adakah yang tahu Bagaimana saya bisa memuat objek saya 'banana'? Terima kasih!

EDIT: Seperti yang disarankan beberapa dari Anda, saya katakan:

>>> import pickle
>>> file = open("Fruits.obj",'rb')

Tidak ada masalah, tapi yang saya taruh selanjutnya adalah:

>>> object_file = pickle.load(file)

Dan saya mengalami kesalahan:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
EOFError
Peterstone
sumber

Jawaban:

74

Adapun masalah kedua Anda:

 Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "C:\Python31\lib\pickle.py", line
 1365, in load encoding=encoding,
 errors=errors).load() EOFError

Setelah Anda membaca konten file, penunjuk file akan berada di akhir file - tidak akan ada data lebih lanjut untuk dibaca. Anda harus memundurkan file agar dapat dibaca dari awal lagi:

file.seek(0)

Apa yang biasanya ingin Anda lakukan adalah menggunakan pengelola konteks untuk membuka file dan membaca data darinya. Dengan cara ini, file akan secara otomatis ditutup setelah blok selesai dieksekusi, yang juga akan membantu Anda mengatur operasi file Anda menjadi potongan yang berarti.

Akhirnya, cPickle adalah implementasi yang lebih cepat dari modul acar di C. Jadi:

In [1]: import cPickle

In [2]: d = {"a": 1, "b": 2}

In [4]: with open(r"someobject.pickle", "wb") as output_file:
   ...:     cPickle.dump(d, output_file)
   ...:

# pickle_file will be closed at this point, preventing your from accessing it any further

In [5]: with open(r"someobject.pickle", "rb") as input_file:
   ...:     e = cPickle.load(input_file)
   ...:

In [7]: print e
------> print(e)
{'a': 1, 'b': 2}
Jim Brissom
sumber
Jenis struktur data apakah ini 'd = {"a": 1, "b": 2}'?
Peterstone
1
@Peterstone: {"a": 1, "b": 2}membuat kamus dengan tombol "a"dan "b"di dalamnya. Ini disebut ekspresi tampilan kamus dalam dokumentasi online. Ini hanyalah salah satu dari beberapa cara berbeda sebuah objek bertipe dict, yang merupakan salah satu dari beberapa tipe data bawaan standar yang tersedia dengan Python, dapat dibangun.
martineau
2
Mengapa huruf 'r' melanjutkan nama file? Saya tidak melihatnya di dokumen. Juga, membuat sulit untuk menggunakan variabel untuk nama file.
SherylHohman
7
Melihat jawaban ini hari ini dan memperhatikannya hanya berlaku untuk Python 2.x. Di Python 3.x, seseorang harus langsung menggunakan pickleyang akan mengimpor cpicklesecara otomatis jika bisa. docs.python.org/3.1/whatsnew/3.0.html#library-changes
Eskapp
41

Pekerjaan berikut untuk saya:

class Fruits: pass

banana = Fruits()

banana.color = 'yellow'
banana.value = 30

import pickle

filehandler = open("Fruits.obj","wb")
pickle.dump(banana,filehandler)
filehandler.close()

file = open("Fruits.obj",'rb')
object_file = pickle.load(file)
file.close()

print(object_file.color, object_file.value, sep=', ')
# yellow, 30
martineau.dll
sumber
Ini berhasil bagi saya, tetapi yang saya kejar adalah menutup sesi, membuka sesi baru, dan memuat apa yang saya simpan di sesi sebelumnya. Saya menutup sesi setelah meletakkan baris "filehandler.close ()" dan saya membuka yang baru dan saya meletakkan sisa kode Anda, kemudian setelah meletakkan "object_file = pickle.load (file)" saya mendapatkan kesalahan ini: Traceback ( panggilan terakhir terakhir): File "<pyshell # 5>", baris 1, di <module> object_file = pickle.load (file) File "C: \ Python31 \ lib \ pickle.py", baris 1365, dalam penyandian beban = pengkodean, kesalahan = kesalahan) .load () AttributeError: objek 'module' tidak memiliki atribut 'Buah'
Peterstone
3
@Peterstone: Di sesi kedua Anda harus memiliki definisi yang sudah class Fruitsditentukan sehingga pickle.load()dapat menyusun kembali objek dari data yang disimpan di file biner. Praktik terbaik untuk hal semacam ini adalah dengan meletakkan class Fruitsdefinisi dalam file .py terpisah (menjadikannya modul kustom) dan kemudian importmodul atau item darinya kapan pun diperlukan (yaitu, kedua sesi). Misalnya jika Anda memasukkannya ke dalam file bernama MyDataDefs.pymaka Anda bisa menulis from MyDataDefs import Fruits. Beri tahu saya jika ini tidak jelas dan saya akan memperbarui jawaban saya sesuai dengan itu.
martineau
Sebenarnya PEP 8 merekomendasikan menggunakan semua karakter huruf kecil untuk nama modul, jadi contoh di akhir komentar terakhir saya seharusnya ada dalam file bernama my_data_defs.pyusing from my_data_defs import Fruits.
martineau
24

Anda juga lupa membacanya sebagai biner.

Di bagian menulis Anda, Anda memiliki:

open(b"Fruits.obj","wb") # Note the wb part (Write Binary)

Di bagian baca Anda memiliki:

file = open("Fruits.obj",'r') # Note the r part, there should be a b too

Jadi gantilah dengan:

file = open("Fruits.obj",'rb')

Dan itu akan berhasil :)


Adapun kesalahan kedua Anda, kemungkinan besar disebabkan oleh tidak menutup / menyinkronkan file dengan benar.

Coba sedikit kode ini untuk menulis:

>>> import pickle
>>> filehandler = open(b"Fruits.obj","wb")
>>> pickle.dump(banana,filehandler)
>>> filehandler.close()

Dan ini (tidak berubah) untuk dibaca:

>>> import pickle
>>> file = open("Fruits.obj",'rb')
>>> object_file = pickle.load(file)

Versi yang lebih rapi akan menggunakan withpernyataan tersebut.

Untuk menulis:

>>> import pickle
>>> with open('Fruits.obj', 'wb') as fp:
>>>     pickle.dump(banana, fp)

Untuk dibaca:

>>> import pickle
>>> with open('Fruits.obj', 'rb') as fp:
>>>     banana = pickle.load(fp)
Wolph
sumber
1
Saya menggunakan versi Anda yang menggunakan pernyataan with dan saya mendapatkan pesan ini: Traceback (panggilan terakhir terakhir): File "<pyshell # 20>", baris 1, di <module> print (banana.color) AttributeError: 'Fruits' objek tidak memiliki atribut 'warna'
Peterstone
17

Selalu buka dalam mode biner, dalam hal ini

file = open("Fruits.obj",'rb')
ismail
sumber
6

Anda tidak membuka file dalam mode biner.

open("Fruits.obj",'rb')

Harus bekerja.

Untuk kesalahan kedua Anda, file kemungkinan besar kosong, yang berarti Anda tidak sengaja mengosongkannya atau menggunakan nama file yang salah atau semacamnya.

(Ini dengan asumsi Anda benar-benar menutup sesi Anda. Jika tidak, maka itu karena Anda tidak menutup file antara tulis dan baca).

Saya menguji kode Anda, dan berhasil.

Lennart Regebro
sumber
3

Sepertinya Anda ingin menyimpan instance kelas Anda di seluruh sesi, dan menggunakan pickleadalah cara yang tepat untuk melakukan ini. Namun, ada paket bernama kleptoyang mengabstraksi penyimpanan objek ke antarmuka kamus, sehingga Anda bisa memilih untuk mengambil objek dan menyimpannya ke file (seperti yang diperlihatkan di bawah), atau mengacak objek dan menyimpannya ke database, atau sebagai ganti gunakan acar, gunakan json, atau banyak pilihan lainnya. Hal yang menyenangkan tentang kleptoini adalah dengan mengabstraksi ke antarmuka umum, itu membuatnya mudah sehingga Anda tidak perlu mengingat detail tingkat rendah tentang cara menyimpan melalui pengawetan ke file, atau sebaliknya.

Perhatikan bahwa Ini berfungsi untuk atribut kelas yang ditambahkan secara dinamis, yang tidak dapat dilakukan oleh acar ...

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from klepto.archives import file_archive 
>>> db = file_archive('fruits.txt')
>>> class Fruits: pass
... 
>>> banana = Fruits()
>>> banana.color = 'yellow'
>>> banana.value = 30
>>> 
>>> db['banana'] = banana 
>>> db.dump()
>>> 

Lalu kita restart…

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from klepto.archives import file_archive
>>> db = file_archive('fruits.txt')
>>> db.load()
>>> 
>>> db['banana'].color
'yellow'
>>> 

Klepto bekerja pada python2 dan python3.

Dapatkan kodenya di sini: https://github.com/uqfoundation

Mike McKerns
sumber
1

Anda dapat menggunakan anycache untuk melakukan pekerjaan itu untuk Anda. Dengan asumsi Anda memiliki fungsi myfuncyang membuat instance:

from anycache import anycache

class Fruits:pass

@anycache(cachedir='/path/to/your/cache')    
def myfunc()
    banana = Fruits()
    banana.color = 'yellow'
    banana.value = 30
return banana

Anycache memanggil myfuncpertama kali dan mengambil hasilnya ke file dengan cachedirmenggunakan pengenal unik (tergantung pada nama fungsi dan argumen) sebagai nama file. Pada proses yang berurutan, objek acar dimuat.

Jika cachedirdipertahankan antara proses python, objek acar diambil dari proses python sebelumnya.

Argumen fungsi juga diperhitungkan. Implementasi yang direfraktor berfungsi juga:

from anycache import anycache

class Fruits:pass

@anycache(cachedir='/path/to/your/cache')    
def myfunc(color, value)
    fruit = Fruits()
    fruit.color = color
    fruit.value = value
return fruit
c0fec0de
sumber