Я пишу класс сопоставления, который сохраняется на диске. В настоящее время я разрешаю только ключи str
, но было бы неплохо, если бы я мог использовать еще пару типов: возможно, до всего, что можно хэшировать (т. Е. Те же требования, что и для встроенного dict
), но более разумно, я бы принял строку , unicode, int и кортежи этих типов.
С этой целью я хотел бы вывести детерминистическую схему сериализации.
Вариант 1 - травление ключа
Первой мыслью было использовать модуль pickle (или cPickle) для сериализации ключа, но я заметил, что выходные данные pickle
и cPickle
не соответствуют друг другу:
>>> import pickle
>>> import cPickle
>>> def dumps(x):
... print repr(pickle.dumps(x))
... print repr(cPickle.dumps(x))
...
>>> dumps(1)
'I1\n.'
'I1\n.'
>>> dumps('hello')
"S'hello'\np0\n."
"S'hello'\np1\n."
>>> dumps((1, 2, 'hello'))
"(I1\nI2\nS'hello'\np0\ntp1\n."
"(I1\nI2\nS'hello'\np1\ntp2\n."
Существует ли какая-либо комбинация реализации / протокола pickle
, которая является детерминированной для некоторого набора типов (например, можно использовать cPickle
только с протоколом 0)?
Вариант 2 - Repr и ast.literal_eval
Другой вариант - использовать repr
для сброса и ast.literal_eval
для загрузки. Я написал функцию, чтобы определить, выживет ли данный ключ в этом процессе (он довольно консервативен для типов, которые он позволяет):
def is_reprable_key(key):
return type(key) in (int, str, unicode) or (type(key) == tuple and all(
is_reprable_key(x) for x in key))
Вопрос для этого метода заключается в том, является ли repr
сам по себе детерминированным для типов, которые я здесь разрешил. Я считаю, что это не выдержит барьер версии 2/3 из-за изменения литералов str / unicode. Это также не будет работать для целых чисел, где 2**32 - 1 < x < 2**64
переходит между 32 и 64-битными платформами. Существуют ли другие условия (т. Е. Строки по-разному сериализуются при разных условиях в одном и том же интерпретаторе)? Редактировать: Я просто пытаюсь понять условия, которые это нарушает, не обязательно преодолевать их.
Вариант 3: Пользовательский репр
Другой вариант, который, вероятно, излишний, - написать свой собственный repr
, который сглаживает вещи repr, с которыми я знаю (или подозреваю, что это может быть) проблема. Я только что написал пример здесь: http://gist.github.com/423945
(Если все это с треском проваливается, тогда я могу сохранить хэш ключа вместе с указателем ключа и значения, а затем перебрать строки, в которых есть совпадающий хеш, ища тот, который распределяется по ожидаемому ключу, но это действительно усложняет некоторые другие вещи, и я бы предпочел этого не делать. Редактировать: Оказывается , что встроенный hash
также не является детерминированным на разных платформах. Поцарапайте это.)
Есть идеи?