Nesneleri kaydetme ve yükleme ve turşu kullanma


114

pickleModülü kullanarak nesneleri kaydetmeye ve yüklemeye çalışıyorum .
Önce nesnelerimi beyan ederim:

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

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

Bundan sonra 'Fruits.obj' adlı bir dosyayı açtım (daha önce yeni bir .txt dosyası oluşturdum ve 'Fruits.obj' adını değiştirdim):

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

Bunu yaptıktan sonra oturumumu kapatıyorum ve yenisine başladım ve bir sonrakini koydum (kaydedilmesi gereken nesneye erişmeye çalışıyorum):

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

Ama şu mesajı aldım:

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

Ne yapacağımı bilmiyorum çünkü bu mesajı anlamıyorum. 'Muz' nesnemi nasıl yükleyebileceğimi bilen var mı? Teşekkür ederim!

DÜZENLEME: Bazılarınızın iddia ettiği gibi şunu söylüyorum:

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

Sorun olmadı, ancak sonraki koyduğum şey şuydu:

>>> object_file = pickle.load(file)

Ve hatam var:

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


Yanıtlar:


74

İkinci probleminize gelince:

 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

Dosyanın içeriğini okuduktan sonra, dosya işaretçisi dosyanın sonunda olacaktır - okunacak başka veri olmayacaktır. Yeniden baştan okunması için dosyayı geri sarmanız gerekir:

file.seek(0)

Yine de genellikle yapmak istediğiniz şey, dosyayı açmak ve içindeki verileri okumak için bir bağlam yöneticisi kullanmaktır. Bu şekilde, bloğun yürütülmesi bittikten sonra dosya otomatik olarak kapatılacak ve bu da dosya işlemlerinizi anlamlı parçalar halinde düzenlemenize yardımcı olacaktır.

Son olarak, cPickle, C'de turşu modülünün daha hızlı bir uygulamasıdır. Yani:

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}

Bu 'd = {"a": 1, "b": 2}' ne tür bir veri yapısıdır?
Peterstone

1
@Peterstone: {"a": 1, "b": 2}anahtarları "a"ve "b"içinde bulunan bir sözlük oluşturur . Buna, çevrimiçi belgelerde sözlük gösterim ifadesi adı verilir . dictPython'da bulunan birkaç standart yerleşik veri türünden biri olan bir nesnenin oluşturulabileceği birkaç farklı yoldan sadece biridir .
martineau

2
Neden 'r' harfi dosya adıyla devam ediyor? Bunu belgelerde göremiyorum. Ayrıca dosya adı için bir değişken kullanmayı zorlaştırır.
SherylHohman

7
Bugün bu yanıta bakıp farketmek yalnızca Python 2.x için geçerlidir. Python 3.x'te, eğer kapanırsa otomatik olarak pickleiçe aktarılacak olan kişi doğrudan kullanılmalıdır cpickle. docs.python.org/3.1/whatsnew/3.0.html#library-changes
Eskapp

41

Aşağıdakiler benim için çalışıyor:

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

Bu bende işe yarıyor, ancak peşinde olduğum şey bir oturumu kapatmak, yeni bir oturum açmak ve geçmiş bir oturumda kaydettiğim şeyi yüklemek. "Filehandler.close ()" satırını koyduktan sonra oturumu kapatıyorum ve yeni bir tane açıyorum ve kodunuzun geri kalanını koyuyorum, ardından "object_file = pickle.load (file)" yazdıktan sonra şu hatayı alıyorum: Traceback ( en son çağrı son): Dosya "<pyshell # 5>", satır 1, <module> object_file = pickle.load (dosya) Dosya "C: \ Python31 \ lib \ pickle.py", satır 1365, yük kodlamasında = kodlama, hatalar = hatalar) .load () AttributeError: 'modül' nesnesinin 'Meyveler' özniteliği yok
Peterstone

3
@Peterstone: İkinci oturumda , nesneyi ikili dosyaya kaydedilen verilerden yeniden oluşturabilmek için class Fruitstanımlanmış bir tanıma sahip olmanız gerekir pickle.load(). Bu tür şeyler için en iyi uygulama, class Fruitstanımı ayrı bir .py dosyasına (onu özel bir modül haline getirerek) ve ardından importgerektiğinde bu modülü veya ondan öğeleri (yani her iki oturum) koymaktır . Örneğin, isimli bir dosyaya koyarsanız MyDataDefs.pyyazabilirsiniz from MyDataDefs import Fruits. Bu net değilse bana bildirin ve cevabımı buna göre güncelleyeceğim.
martineau

Aslında PEP 8 , modül adları için tüm küçük harfli karakterlerin kullanılmasını önerir , bu nedenle son yorumumun sonundaki örnek, my_data_defs.pyusing adlı bir dosyada olmalıdır from my_data_defs import Fruits.
martineau

24

Siz de ikili olarak okumayı unutuyorsunuz.

Yazma bölümünüzde:

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

Okunan bölümde:

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

Öyleyse şununla değiştirin:

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

Ve işe yarayacak :)


İkinci hatanıza gelince, bunun nedeni büyük olasılıkla dosyayı düzgün şekilde kapatmamak / senkronize etmemek.

Yazmak için bu kod parçasını deneyin:

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

Ve bunu (değişmedi) okumak için:

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

İfadeyi daha temiz bir versiyon kullanacaktır with.

Yazmak için:

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

Okumak için:

>>> import pickle
>>> with open('Fruits.obj', 'rb') as fp:
>>>     banana = pickle.load(fp)

1
With ifadesini kullanan sürümünüzü kullanıyorum ve şu iletiyi alıyorum: Traceback (en son çağrı son): Dosya "<pyshell # 20>", satır 1, <module> print (banana.color) AttributeError: 'Fruits' nesnenin 'renk' özelliği yoktur
Peterstone

17

Bu durumda her zaman ikili modda aç

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

6

Dosyayı ikili modda açmadınız.

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

Çalışmalı.

İkinci hatanız için, dosya büyük olasılıkla boştur, bu da yanlışlıkla onu boşalttığınız veya yanlış dosya adı veya başka bir şey kullandığınız anlamına gelir.

(Bu, oturumunuzu gerçekten kapattığınızı varsayar. Değilse, yazma ve okuma arasında dosyayı kapatmadığınız içindir).

Kodunuzu test ettim ve işe yarıyor.


3

Görünüşe göre sınıf örneklerinizi oturumlar arasında kaydetmek istiyorsunuz ve kullanmak picklebunu yapmanın iyi bir yoludur. Ancak, kleptonesnelerin bir sözlük arayüzüne kaydedilmesini özetleyen bir paket var , böylece nesneleri seçip bir dosyaya kaydetmeyi (aşağıda gösterildiği gibi) veya nesneleri toplayıp bir veritabanına kaydetmeyi veya turşu kullanmak json veya diğer birçok seçeneği kullanın. İşin güzel yanı klepto, ortak bir arayüze soyutlayarak, bunu kolaylaştırmasıdır, böylece bir dosyaya dekapaj yoluyla veya başka bir şekilde nasıl kaydedileceğine ilişkin düşük düzeyli ayrıntıları hatırlamak zorunda kalmazsınız.

Turşu'nun yapamayacağı dinamik olarak eklenen sınıf nitelikleri için çalıştığını unutmayın ...

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

Sonra yeniden başlıyoruz…

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 python2 ve python3 üzerinde çalışır.

Kodu buradan alın: https://github.com/uqfoundation


1

İşi sizin yerinize yapmak için herhangi bir önbelleği kullanabilirsiniz . Örneği myfuncoluşturan bir işleve sahip olduğunuzu varsayarsak :

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 myfuncilk seferde çağırır ve sonucu dosya cachediradı olarak benzersiz bir tanımlayıcı (işlev adına ve argümanlara bağlı olarak ) kullanarak bir dosyaya toplar . Herhangi bir ardışık çalışmada, turşu nesnesi yüklenir.

Eğer cachedirpiton koşular arasında korunur, turşu nesne önceki piton vadede alınır.

Fonksiyon argümanları da dikkate alınır. Yeniden düzenlenen bir uygulama da aynı şekilde çalışır:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.