dbfile = open(‘people-pickle’, ‘rb’) db = pickle.load(dbfile) dbfile.close()
db[‘sue’][‘pay’] *= 1.10 db[‘tom’][‘name’] = ‘Tom Tom’
dbfile = open(‘people-pickle’, ‘wb’) pickle.dump(db, dbfile) dbfile.close()
Обратите внимание, что после изменения записи в файл сохраняется вся база данных целиком, как и при использовании простого текстового файла; это может занимать продолжительное время, если база данных имеет значительный объем, но мы пока не будем беспокоиться об этом. Ниже приводится пример запуска сценариев
...\PP4E\Preview> python update_db_pickle.py ...\PP4E\Preview> python dump_db_pickle.py
bob =>
{‘pay’: 30000, ‘job’: ‘dev’, ‘age’: 42, ‘name’: ‘Bob Smith’}
sue =>
{‘pay’: 44000.0, ‘job’: ‘hdw’, ‘age’: 45, ‘name’: ‘Sue Jones’} tom =>
{‘pay’: 0, ‘job’: None, ‘age’: 50, ‘name’: ‘Tom Tom'}
Sue Jones
Как мы узнаем в главе 17, модуль pickle поддерживает объекты практически любых типов - списки, словари, экземпляры классов, вложенные структуры и многие другие. Там же мы узнаем о текстовых и двоичных протоколах преобразования сохраняемых данных. В Python 3 для представления сохраненных данных все протоколы используют объекты типа bytes, чем обусловлена необходимость открывать файлы pickle в двоичном режиме, независимо от используемого протокола. Кроме того, как будет показано далее в этой главе, модуль pickle и его формат представления данных используется модулем shelve и базами данных ZODB, а в случае экземпляров классов сохраняются не только данные в объектах, но и их поведение.
Модуль pickle фактически является гораздо более универсальным, чем можно было бы заключить из представленных примеров. Поскольку сериализованные данные принимаются любыми объектами, поддерживающими интерфейс, совместимый с файлами, методы dump и load модуля pickle могут использоваться для передачи объектов Python через различные среды распространения информации. С помощью сетевых сокетов, например, можно организовать передачу сериализованных объектов Python по сети и тем самым обеспечить альтернативу более тяжелым протоколам, таким как SOAP и XML-RPC.
Работа модуля pickle с отдельными записями
Как упоминалось выше, один из потенциальных недостатков примеров, представленных в этом разделе до настоящего момента, состоит в том, что они могут оказаться слишком медленными при работе с очень большими базами данных: так как для изменения единственной записи необходимо загружать и сохранять базу данных целиком, при таком решении значительная часть времени будет тратиться впустую. Мы могли бы избежать этого, предусмотрев сохранение каждой записи базы данных в отдельном файле. Следующие три примера демонстрируют, как это можно реализовать, - сценарий из примера 1.8 сохраняет каждую запись в отдельном файле, где в качестве имени файла используется уникальный ключ записи, к которому добавляется расширение
from initdata import bob, sue, tom import pickle
for (key, record) in [(‘bob’, bob), (‘tom’, tom), (‘sue’, sue)]: recfile = open(key + ‘.pkl’, ‘wb’) pickle.dump(record, recfile) recfile.close()
Следующий сценарий, представленный в примере 1.9, выводит содержимое всей базы данных, используя модуль glob для подстановки имен файлов и тем самым для выбора всех файлов с расширением
import pickle, glob
for filename in glob.glob(‘*.pkl’): # для ‘bob’,’sue’,’tom’
recfile = open(filename, ‘rb’) record = pickle.load(recfile) print(filename, ‘=>\n ‘, record)
suefile = open(‘sue.pkl’, ‘rb’)
print(pickle.load(suefile)[‘name’]) # извлечь имя Сью
Наконец, сценарий в примере 1.10 обновляет содержимое базы данных, извлекая запись из ее файла, изменяя объект в памяти и затем сохраняя его обратно в файл с помощью модуля pickle. На этот раз для внесения изменений необходимо извлечь и сохранить единственную запись, а не всю базу данных.
import pickle
suefile = open(‘sue.pkl’, ‘rb’)
sue = pickle.load(suefile)
suefile.close()
sue[‘pay’] *= 1.10
suefile = open(‘sue.pkl’, ‘wb’)
pickle.dump(sue, suefile)
suefile.close()