Пролог


В своей работе у меня, время от времени, возникает желание изменить поведение того или иного инструмента: сделать работу с ним привычней, 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)


  1. griganton
    05.10.2016 19:15
    +2

    В мире питона иногда кажется что все написано до нас…
    Очень похоже на модуль redis-collections


    1. Amka
      05.10.2016 20:12

      О, вы совершенно правы, боюсь я просто недостаточно хорошо гуглил.


  1. icoz
    05.10.2016 19:15
    +2

    Ссылки на гитхаб раскидайте почаще. И уж точно рядом с фразой про pull-реквесты.
    А в целом отличная идея. Одобряю. Может быть теперь попробую redis.


  1. Tiendil
    05.10.2016 19:58
    +1

    Explicit is better than implicit


  1. 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 строк!


    1. Amka
      06.10.2016 12:35

      У меня нет опыта использования Redis в больших проектах и, я более чем уверен, что такая простая абстракция не потянет необходимый функционал. Мысль с prefix мне нравится, думаю стоит добавить подобную возможность.
      Ещё много над чем есть подумать и что реализовать, пока лишь самое начало.