Подтвердить что ты не робот

Получение значений с правильным типом в Redis

Я использую redis в своем приложении python для хранения простых значений, таких как счетчики и списки штампов времени, но пытаясь получить счетчик и сравнивая его с номером, я столкнулся с проблемой.

Если я это сделаю:

import redis
...
myserver = redis.Redis("localhost")
myserver.set('counter', 5)

а затем попытайтесь получить это значение следующим образом:

if myserver.get('counter') < 10:
     myserver.incr('counter')

то я получаю ошибку типа в выражении if, потому что я сравниваю '5' < 10, что означает Я сохраняю целочисленное значение и получаю строку (которую можно рассматривать как другое значение).

Мой вопрос: это должно работать так? Я имею в виду его очень простой тип, я понимаю, если мне нужно разбирать объекты, но int? Кажется, что я делаю что-то неправильно.

Есть ли какая-либо конфигурация, которую мне не хватает?

Есть ли способ сделать redis возвращать правильный тип, а не всегда строку? Я говорю это, потому что это то же самое для списков и дат или даже значений с плавающей запятой.

Может ли это быть проблемой с клиентом redis-py, который я использую, и не перерисовываю себя?

4b9b3361

Ответ 1

С технической точки зрения, вам нужно позаботиться об этом самостоятельно.

Однако посмотрите эту ссылку, особенно в части их README, которая ссылается на парсеры и ответные обратные вызовы, возможно, что-то, что вы можете использовать. Вопрос в том, будет ли это лишним для вас или нет.

Ответ 2

Как сказал @favoretti, ответные обратные вызовы будут делать трюк. Это совсем не сложно, только одна строка, и все позаботятся.

In [2]: import redis
In [3]: r = redis.Redis()
In [10]: r.set_response_callback('HGET', float)
In [11]: r.hget('myhash', 'field0')
Out[11]: 4.6

для hmget, он возвращает список строк, а не одну строку, поэтому вам нужно построить немного более полную функцию обратного вызова:

In [12]: r.set_response_callback('HMGET', lambda l: [float(i) for i in l])

In [13]: r.hmget('myhash', 'field0')
Out[13]: [4.6]

для hgetall.

Ответ 3

Похоже, что redis сохраняет свои данные:

redis 127.0.0.1:6379> set counter 5
OK
redis 127.0.0.1:6379> type counter
string
redis 127.0.0.1:6379> incr counter
(integer) 6
redis 127.0.0.1:6379> type counter
string

Если вы действительно этого захотите, возможно, вы можете обезвредить клиенту redis-py для вывода типов данных.

Ответ 4

Вы можете установить decode_respone как True

redis.StrictRedis(host="localhost", port=6379, db=0, decode_responses=True)

Ответ 5

Вот мой тест. Два redis-соединения: один возвращает тип int, другой float

import redis

age_field = redis.Redis()
age_field.set_response_callback('HGET', int)
age_field.hget('foo', 'age')
# OUT: 40
a =age_field.hget('foo', 'age')
type(a)
# OUT: <type 'int'>

gpa_field = redis.Redis()
gpa_field.set_response_callback('HGET', float)
gpa_field.hget('foo', 'gpa')
# OUT: 2.5
b = gpa_field.hget('foo', 'gpa')
type(b)
# OUT: <type 'float'>

Ответ 6

Хотя использование set_response_callback отлично подходит для простых типов данных, если вы задаетесь вопросом о самом быстром и простом set_response_callback хранения таких вещей, как словари, списки, кортежи - и сохранении нативных типов данных Python, которые они могут или не могут содержать - Я рекомендую использовать встроенную в Python библиотеку pickle:

# Imports and simplified client setup
>>> import pickle
>>> import redis
>>> client = redis.Redis()
# Store a dictionary
>>> to_store = {'a': 1, 'b': 'A string!', 'c': [1, True, False, 14.4]}
>>> client.set('TestKey', pickle.dumps(to_store))
True
# Retrieve the dictionary you just stored.
>>> retrieved = pickle.loads(client.get('TestKey'))
{'a': 1, 'b': 'A string!', 'c': [1, True, False, 14.4]}

Вот простой клиент, который уменьшит шаблон pickle в приведенном выше примере и предоставит вам чистый интерфейс для хранения и извлечения собственных типов данных Python в Redis:

"""Redis cache."""
import pickle
import redis

redis_host = redis.Redis()


class PythonNativeRedisClient(object):
    """
    A redis cache client.

    Uses pickle for setting and getting so native datatypes are preserved.
    """

    def __init__(self, redis_host=redis_host):
        """Initialize client."""
        self.client = redis_host

    def set(self, key, value, **kwargs):
        """Store a value in Redis."""
        return self.client.set(key, pickle.dumps(value), **kwargs)

    def get(self, key):
        """Retrieve a value from Redis."""
        val = self.client.get(key)
        if val:
            return pickle.loads(val)
        return None

redis_client = PythonNativeRedisClient()

Использование:

>>> from some_module import redis_client
>>> to_store = {'a': 1, 'b': 'A string!', 'c': [1, True, False, 14.4]}
>>> client.set('TestKey', to_store)
True
>>> retrieve = client.get('TestKey')
{'a': 1, 'b': 'A string!', 'c': [1, True, False, 14.4]}