Python Language
odłożyć na półkę
Szukaj…
Wprowadzenie
Półka jest modułem pythonowym służącym do przechowywania obiektów w pliku. Moduł półki implementuje trwałe przechowywanie dowolnych obiektów Pythona, które mogą być marynowane przy użyciu interfejsu API podobnego do słownika. Moduł półki może być używany jako prosta opcja trwałego przechowywania obiektów Python, gdy relacyjna baza danych jest nadmierna. Dostęp do półki można uzyskać za pomocą klawiszy, tak jak w przypadku słownika. Wartości są marynowane i zapisywane w bazie danych utworzonej i zarządzanej przez anydbm.
Uwagi
Uwaga: Nie polegaj na automatycznym zamykaniu półki; zawsze jawnie wywołuj close()
gdy już go nie potrzebujesz, lub użyj shelve.open()
jako menedżera kontekstu:
with shelve.open('spam') as db:
db['eggs'] = 'eggs'
Ostrzeżenie:
Ponieważ shelve
moduł jest wspierany przez pickle
, jest niepewny, aby załadować półkę z niezaufanych źródeł. Podobnie jak w przypadku marynaty, załadowanie półki może wykonać dowolny kod.
Ograniczenia
1 . Wybór pakietu bazy danych (np. Dbm.ndbm lub dbm.gnu) zależy od tego, który interfejs jest dostępny. Dlatego otwarcie bazy danych bezpośrednio za pomocą dbm nie jest bezpieczne. Baza danych podlega także (niestety) ograniczeniom dbm, jeśli jest używana - oznacza to, że (piklowana reprezentacja) obiektów przechowywanych w bazie danych powinna być dość mała, aw rzadkich przypadkach kolizje kluczy mogą spowodować, że baza danych odmówić aktualizacji.
2. Moduł półki nie obsługuje równoczesnego dostępu do odczytu / zapisu do półek. (Wiele jednoczesnych dostępów do odczytu jest bezpiecznych.) Gdy program ma otwartą półkę do pisania, żaden inny program nie powinien mieć otwartej półki do odczytu lub zapisu. Do rozwiązania tego problemu można użyć blokowania plików w systemie Unix, ale różni się to w zależności od wersji systemu Unix i wymaga wiedzy na temat zastosowanej implementacji bazy danych.
Przykładowy kod półki
Aby odłożyć obiekt na półkę, najpierw zaimportuj moduł, a następnie przypisz wartość obiektu w następujący sposób:
import shelve
database = shelve.open(filename.suffix)
object = Object()
database['key'] = object
Podsumowując interfejs (klucz to ciąg, dane to dowolny obiekt):
import shelve
d = shelve.open(filename) # open -- file may get suffix added by low-level
# library
d[key] = data # store data at key (overwrites old data if
# using an existing key)
data = d[key] # retrieve a COPY of data at key (raise KeyError
# if no such key)
del d[key] # delete data stored at key (raises KeyError
# if no such key)
flag = key in d # true if the key exists
klist = list(d.keys()) # a list of all existing keys (slow!)
# as d was opened WITHOUT writeback=True, beware:
d['xx'] = [0, 1, 2] # this works as expected, but...
d['xx'].append(3) # *this doesn't!* -- d['xx'] is STILL [0, 1, 2]!
# having opened d without writeback=True, you need to code carefully:
temp = d['xx'] # extracts the copy
temp.append(5) # mutates the copy
d['xx'] = temp # stores the copy right back, to persist it
# or, d=shelve.open(filename,writeback=True) would let you just code
# d['xx'].append(5) and have it work as expected, BUT it would also
# consume more memory and make the d.close() operation slower.
d.close() # close it
Tworzenie nowej półki
Najprostszym sposobem użycia shelve jest użycie klasy DbfilenameShelf . Do przechowywania danych używa anydbm. Możesz użyć tej klasy bezpośrednio lub po prostu wywołać shelve.open () :
import shelve
s = shelve.open('test_shelf.db')
try:
s['key1'] = { 'int': 10, 'float':9.5, 'string':'Sample data' }
finally:
s.close()
Aby ponownie uzyskać dostęp do danych, otwórz półkę i użyj jej jak słownika:
import shelve
s = shelve.open('test_shelf.db')
try:
existing = s['key1']
finally:
s.close()
print existing
Jeśli uruchomisz oba przykładowe skrypty, powinieneś zobaczyć:
$ python shelve_create.py
$ python shelve_existing.py
{'int': 10, 'float': 9.5, 'string': 'Sample data'}
Moduł dbm nie obsługuje wielu aplikacji zapisujących do tej samej bazy danych jednocześnie. Jeśli wiesz, że twój klient nie będzie modyfikował półki, możesz powiedzieć półce, aby otworzyła bazę danych tylko do odczytu.
import shelve
s = shelve.open('test_shelf.db', flag='r')
try:
existing = s['key1']
finally:
s.close()
print existing
Jeśli program próbuje zmodyfikować bazę danych, gdy jest ona otwarta tylko do odczytu, generowany jest wyjątek błędu dostępu. Typ wyjątku zależy od modułu bazy danych wybranego przez anydbm podczas tworzenia bazy danych.
Odpisać
Półki domyślnie nie śledzą modyfikacji obiektów lotnych. Oznacza to, że jeśli zmienisz zawartość przedmiotu przechowywanego na półce, musisz wyraźnie zaktualizować półkę, ponownie przechowując przedmiot.
import shelve
s = shelve.open('test_shelf.db')
try:
print s['key1']
s['key1']['new_value'] = 'this was not here before'
finally:
s.close()
s = shelve.open('test_shelf.db', writeback=True)
try:
print s['key1']
finally:
s.close()
W tym przykładzie słownik w kluczu „1” nie jest ponownie przechowywany, więc po ponownym otwarciu półki zmiany nie zostały zachowane.
$ python shelve_create.py
$ python shelve_withoutwriteback.py
{'int': 10, 'float': 9.5, 'string': 'Sample data'}
{'int': 10, 'float': 9.5, 'string': 'Sample data'}
Aby automatycznie wychwytywać zmiany w lotnych obiektach przechowywanych na półce, otwórz półkę z włączonym zapisem. Flaga zapisu zwrotnego powoduje, że półka zapamiętuje wszystkie obiekty pobrane z bazy danych przy użyciu pamięci podręcznej w pamięci. Każdy obiekt pamięci podręcznej jest również zapisywany z powrotem do bazy danych, gdy półka jest zamknięta.
import shelve
s = shelve.open('test_shelf.db', writeback=True)
try:
print s['key1']
s['key1']['new_value'] = 'this was not here before'
print s['key1']
finally:
s.close()
s = shelve.open('test_shelf.db', writeback=True)
try:
print s['key1']
finally:
s.close()
Mimo że zmniejsza ryzyko błędu programisty i może uczynić trwałość obiektu bardziej przejrzystym, użycie trybu zapisu zwrotnego może nie być pożądane w każdej sytuacji. Pamięć podręczna zużywa dodatkową pamięć, gdy półka jest otwarta, a wstrzymanie zapisywania każdego buforowanego obiektu z powrotem do bazy danych po zamknięciu może zająć więcej czasu. Ponieważ nie ma sposobu, aby stwierdzić, czy obiekty w pamięci podręcznej zostały zmodyfikowane, wszystkie są zapisywane ponownie. Jeśli aplikacja odczytuje dane więcej niż zapisuje, zapisywanie zwrotne doda więcej narzutu, niż możesz chcieć.
$ python shelve_create.py
$ python shelve_writeback.py
{'int': 10, 'float': 9.5, 'string': 'Sample data'}
{'int': 10, 'new_value': 'this was not here before', 'float': 9.5, 'string': 'Sample data'}
{'int': 10, 'new_value': 'this was not here before', 'float': 9.5, 'string': 'Sample data'}