Пролог
В своей работе у меня, время от времени, возникает желание изменить поведение того или иного инструмента: сделать работу с ним привычней, API прозрачней и т. п. Так случилось и когда мне в наследство достался проект, где в качестве хранилища использовался Redis. Несомненно, Python имеет достаточно библиотек для удобной работы с Redis, однако вспоминая, что это именно key-value хранилище, мне не могла не прийти в голову мысль о том, как было бы замечательно работать с ним как с обычным Python-словарём (dict).
Вместо
>>> redis_obj.exist(key)
использовать
>>> key in redis_obj
Сохранять объекты привычным присваиванием:
>>> redis_obj['Planets'] = ['Mercury', 'Venus', 'Earth', 'Mars']
Так и родился на свет Dictator. Dictator имитирует методы класса dict, пряча интерфейс Redis от пользователя.
Установка
Установка крайне проста, как и множество Python библиотек, он доступен в Pypi
$ pip install dictator
Исходные коды с лицензией MIT забирать в хранилище на GitHub.
Использование
Использовать Dictator крайне просто, однако инициализация объектов всё таки отлична от словаря (надо же знать куда подключаться):
>>> dc = Dictator(host='localhost', port=6379, db=0)
Далее с созданным объектом можно работать в привычной манере:
.set(key, value)
>>> dc.set('Planets', ['Mercury', 'Venus', 'Earth']) >>> dc['Stars'] = ['Sun']
.get(key)
>>> dc['Stars'] ['Sun'] >>> dc.get('Planets') ['Mercury', 'Venus', 'Earth']
Можно задать значение, на случай если по ключу
key
не будет ничего найдено
>>> dc.get('Comets', 'No data') 'No data'
.update(other=None, **kwargs)
>>> dc.update({'Stars': ['Sun', 'Vega']}) >>> dc.update(Stars=['Sun'])
.pop(key, default=None)
>>> dc.pop('Stars') ['Sun'] >>> dc.pop('Comets')
.delete(key)
>>> dc.delete('Comets')
or
>>> del dc['Comets']
.keys()
and.values()
>>> dc.keys() ['Planets', 'Stars'] >>> dc.values() [['Mercury', 'Venus', 'Earth']]
.items()
>>> dc.iterms() [('Planets', ['Mercury', 'Venus', 'Earth'])]
и, конечно, итерация с помощью объекта-генератора:
.iterkeys()
.itervalues()
.iteritems()
И это не всё :)
Эпилог
Проект находится в начальной стадии, заботливо задокументирован и украшен.
Fork-и, pull-request-ы и другие issues приветствуются!
GitHub: dictator
Спасибо за внимание!
Комментарии (6)
icoz
05.10.2016 19:15+2Ссылки на гитхаб раскидайте почаще. И уж точно рядом с фразой про pull-реквесты.
А в целом отличная идея. Одобряю. Может быть теперь попробую redis.
buriy
05.10.2016 22:14+4Абстракция в виде одного словаря на всю базу данных — вещь непрактичная для долговременного использования, неплохое её улучшение — namespaces.
Наиболее удобны в подобных плоских базах префиксные области имён:
r = Redis(host='localhost', port=6379, db=0) d = Dictator(r, prefix='planets:') d.set('Mars', 1000) # updates key 'planets:Mars' with value 1000 d['Venus'] = 2000 # gets value for key 'planets:Venus' print 'Mars' in d ...
Но в Redis есть ещё тип данных Hash, который в некоторых случаях заменяет обычные ключи со значениями, и не имеет проблемы с глобальной областью видимости. Для него можно сделать почти такой же интерфейс:
r = Redis(host='localhost', port=6379, db=0) dh = DictatorHash(r, key='Planets') dh.set('Mars', 1000) dh['Venus'] = 2000 print 'Mars' in dc
P.S. А следующим усовершенствованием являются batch-методы: get_many, set_many, delete_many и обобщённый batching в виде redis pipeline, потому что без них любая операция с данными (меньше 100 кб) в основном тратит время на прохождение запроса до базы данных и обратно.
Увы, удобного интерфейса для них в питоне нет, и поэтому приходится забыть про квадратные скобки и «in», которые так хорошо смотрелись в программах из 50 строк!Amka
06.10.2016 12:35У меня нет опыта использования Redis в больших проектах и, я более чем уверен, что такая простая абстракция не потянет необходимый функционал. Мысль с
prefix
мне нравится, думаю стоит добавить подобную возможность.
Ещё много над чем есть подумать и что реализовать, пока лишь самое начало.
griganton
В мире питона иногда кажется что все написано до нас…
Очень похоже на модуль redis-collections
Amka
О, вы совершенно правы, боюсь я просто недостаточно хорошо гуглил.