web-dev-qa-db-fra.com

Obtenir des valeurs avec le bon type dans Redis

J'utilise redis dans mon application python pour stocker des valeurs simples comme des compteurs et des listes d'horodatage, mais en essayant d'obtenir un compteur et en le comparant à un nombre, j'ai rencontré un problème.

Si je fais:

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

et ensuite essayer d'obtenir cette valeur comme ceci:

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

alors j'obtiens une erreur de type dans l'instruction if parce que je compare '5' <10, ce qui signifie je stocke une valeur entière et j'obtiens une chaîne un (qui peut être considéré comme une valeur différente).

Ma question est la suivante: est-ce que cela est censé fonctionner comme ça? Je veux dire que c'est un type très basique, je comprends si je dois analyser des objets mais un int? On dirait que je fais quelque chose de mal.

Y a-t-il une configuration qui me manque?

Est-il possible de faire en sorte que redis retourne le bon type et pas toujours une chaîne? Je le dis parce que c'est la même chose pour les listes et les dates/heures ou même pour les valeurs à virgule flottante.

Cela pourrait-il être un problème avec le client redis-py que j'utilise et non pas avec Redis lui-même?

24
jeruki

Techniquement, vous devez vous en occuper vous-même.

Cependant, jetez un coup d'œil à ce lien , en particulier à la partie de leur README qui fait référence aux analyseurs syntaxiques et aux rappels de réponse, vous pourrez peut-être l'utiliser. La question serait de savoir s’il s’agit d’une surdose pour vous ou non.

14
favoretti

Comme @favoretti l'a dit, les callbacks de réponse feront l'affaire. Ce n'est pas compliqué du tout, juste une ligne et tout sera pris en charge. 

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

pour hmget, il retourne une liste de chaînes, pas une seule, vous devez donc créer une fonction de rappel un peu plus complète:

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]

idem pour hgetall.

14
pingz

On dirait que c'est comme ça que Redis stocke ses données:

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

Si vous vraiment voulez, vous pouvez probablement associer le client redis-py pour déduire des types de données. 

4
Joel Cornett

Vous pouvez définir decode_respone comme True

redis.StrictRedis(Host="localhost", port=6379, db=0, decode_responses=True)
3
Lucas Picoloto

Bien que le recours à set_response_callback convient aux types de données simples, vous pouvez vous demander quelle est la route la plus rapide et la plus facile pour stocker des éléments tels que les dictionnaires, les listes, les tuples - et préserver les types de données natifs python qu’ils peuvent peut-être - may-not contient - je recommande d'utiliser la bibliothèque pickle intégrée de python:

# 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]}

Voici un client simple qui réduira le pickle et le va dans les exemples ci-dessus et vous fournira une interface propre pour le stockage et la récupération des types de données python natifs de et vers Redis:

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

redis_Host = redis.Redis()


class PythonNativeRedisClient(object):
    """A simple redis client for storing and retrieving native python datatypes."""

    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()

Usage:

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

Voici mon test. Deux connexions redis: l'une retourne le type int, l'autre 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'>
0
Jie Bao