shelve
на самом деле очень хороший выбор здесь. Он действует точно так же, как словарь, но подкрепляется BDB (или аналогичным) файлом базы данных ключевого значения, а Python будет обрабатывать все кэширование и т. Д., Поэтому ему не нужно сразу загружать все это в память.
Вот как создать файл полки. Обратите внимание, что полные ключи должны быть строками. Также обратите внимание, что я создаю полку на месте, вместо того, чтобы сначала создавать dict
и откладывать ее. Таким образом, вы избегаете затрат на создание этого гигантского в памяти dict
, что в первую очередь вызывает проблемы.
from contextlib import closing
import shelve
def makedict(shelf):
# Put the real dict-generating code here, obviously
for i in range(500000);
shelf[str(i)] = i
with closing(shelve.open('mydict.shelf', 'c')) as shelf:
makedict(shelf)
И использовать его, на самом деле не читать; оставить его в качестве полки на диске:
from contextlib import closing
import shelve
with closing(shelve.open('mydict.shelf')) as d:
# Put all your actual work here.
print len(d)
Если словарю используя код не может легко вписаться в рамки, заменить with
заявление с простым open
, и явно close
, когда вы закончите.
pickle
, вероятно, не так хорош в идее, потому что вам все равно нужно прочитать все это в памяти. Вероятно, он использует гораздо меньшую временную память и, возможно, дисковое пространство, чем импорт модуля, который определяет гигантский литерал, но все же, имея хеш-таблицу в памяти, которая может быть огромной проблемой. Но вы всегда можете проверить его и посмотреть, насколько хорошо он работает.
Вот как создать файл рассола. Обратите внимание, что вы можете использовать (почти) все, что хотите, в качестве ключа, а не только строки. Тем не менее, вы должны построить целое dict
, прежде чем сможете pickle
его.
import cPickle
def makedict():
# Put the real dict-generating code here, obviously
return {i:i for i in range(500000)}
with open('mydict.pickle', 'wb') as f:
cPickle.dump(d, f, -1)
Это создает файл размером 47 МБ.
Теперь, чтобы использовать его в главном приложении:
import cPickle
def loaddict():
with open('mydict.pickle', 'rb') as f:
return cPickle.load(f)
Те же основные проблемы с pickle
пойти на любой другой формат сохраняемости, который должен быть сохранен и загружен-ли что-то обычай, что вы пишете сами, или что-то стандартное, как JSON или YAML. (Конечно, если вам нужна совместимость с другими программами, особенно на других языках, что-то вроде JSON - это путь.) Вам лучше с базой данных; вопрос только в том, какая база данных.
Преимущество базы данных anydbm
типа является то, что вы можете использовать его, как если бы это было в dict
, не заботясь о том, как загрузить/сохранить/доступ к нему (кроме open
и close
линий). Проблема с anydbm
заключается в том, что она позволяет отображать строки только для строк.
Модуль shelve
эффективно обертывает anydbm
, с травлением каждого значения. Ваши ключи все равно должны быть строками, но ваши значения могут быть почти любыми. Так как ваши ключи являются строками, и у вас нет ссылок со значений на внешние объекты, это довольно прозрачная замена для замены dict
.
Другие варианты - sqlite3
, различные современные базы данных nosql и т. Д. - требуют, чтобы вы изменили способ доступа к данным и даже способ их организации. («Список списков» не является четкой моделью ER.) Конечно, в конечном итоге это может привести к лучшему дизайну, поэтому, если вы думаете, что действительно хотите использовать реляционную модель, рассмотрите эту идею.
Из комментариев, @ekta хотел, чтобы объяснить, почему некоторые ограничения на dbm
и shelve
существуют.
Во-первых, dbm
восходит к 70-м годам. База данных, которая могла бы отображать 8-битные строки в строки просто и эффективно, была довольно сложной сделкой. Было также довольно распространено, что значения всех видов должны храниться в виде их строкового представления, или, если это не так, а затем просто хранить байты, которые представляют собой значение на месте на текущем компьютере. (XML, JSON или даже подгонка индексации, возможно, были слишком дорогими для машин в день или, по крайней мере, для размышлений дня.)
Расширение dbm
для обработки других типов данных для значений не сложно , Их никогда не нужно хэшировать или сравнивать, просто хранить и извлекать без потерь. Поскольку pickle
может обрабатывать очень широкий спектр типов, он не слишком ужасно неэффективен и поставляется с Python, имеет смысл использовать pickle
для этого, так что shelve
делает именно это.
Но ключи - это совсем другая история. Вам нужна кодировка, которая не только без потерь обратима, но также гарантирует, что два значения будут кодироваться в равные байты, если и только если они на самом деле равны. Имейте в виду, что в Python, 1 == True
, но, очевидно, pickle.dumps(1) != pickle.dumps(True)
b'1' != b'True'
и т.д.
Есть много типов, которые могут быть без потерь и равенство-preservingly преобразуются в байт, если вы заботитесь только о том, что тип. Например, для строк Unicode просто используйте UTF-8. (Фактически, shelve
позаботится об этом для вас.) Для 32-разрядных целых чисел со знаком используйте struct.pack('>I')
. Для кортежей из трех строк, кодируйте UTF-8, обратную косую черту-escape и присоединяйте их к символам новой строки. И так далее. Для многих конкретных доменов есть простой ответ; для большинства доменов нет ответа общего назначения.
Итак, если вы хотите использовать dbm
использовать, скажем, кортежи из трех UTF-8 строк в качестве ключей, вы можете написать свою собственную обертку вокруг dbm
(или shelve
). Как и во многих модулях в stdlib, shelve
призван служить полезным примером кода, а также полезной функцией, поэтому у the docs есть ссылка на the source. Это достаточно просто, чтобы новичок должен был понять, как его разветвить, подклассировать или обернуть, чтобы выполнить собственную кодировку ключа.(Обратите внимание: если вы обернете shelve
, вам нужно будет закодировать ваши пользовательские значения до str
, чтобы он мог кодировать это str
в bytes
, если вы его переделаете или подклассируете и переопределите соответствующие методы, вы можете вместо этого кодировать непосредственно bytes
- например, что struct.pack
вызывается выше. Это может быть лучше как для простоты/удобочитаемости, так и для производительности.)
Вы пытались хранить большой словарь в отдельном текстовом файле с помощью JSON? –
Возможно, база данных лучше подходит для хранения данных такого размера или использования текстового формата. –
Можете ли вы выставить отрывок из этого файла? В зависимости от того, насколько близок файл к действительному JSON, вы можете открыть файл для чтения и проанализировать его итеративно, чтобы записать значения в другой файл, который станет более доступным в будущем. –