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?
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.
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
.
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.
Vous pouvez définir decode_respone comme True
redis.StrictRedis(Host="localhost", port=6379, db=0, decode_responses=True)
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]}
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'>