Python 如何在redis中存储一个复杂的对象(使用redis-py)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15219858/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to store a complex object in redis (using redis-py)
提问by yuan
The hmset function can set the value of each field, but I found that if the value itself is a complex structured object, the value return from hget is a serialized string, not the original object
hmset函数可以设置每个字段的值,但是我发现如果值本身是一个复杂的结构化对象,hget返回的值是一个序列化的字符串,而不是原始对象
e.g
例如
images= [{'type':'big', 'url':'....'},
{'type':'big', 'url':'....'},
{'type':'big', 'url':'....'}]
redis = Redis()
redis.hset('photo:1', 'images', images)
i = redis.hget('photo:1', 'images')
print type(i)
the type of i is a string, not a python object, is there any way to solve this problem besides manually parse each fields?
i 的类型是字符串,而不是python 对象,除了手动解析每个字段之外,还有什么方法可以解决这个问题?
采纳答案by Jonatan Hedborg
You can't create nested structures in Redis, meaning you can't (for example) store a native redis list inside a native redis hash-map.
您不能在 Redis 中创建嵌套结构,这意味着您不能(例如)将本机 redis 列表存储在本机 redis 哈希映射中。
If you really need nested structures, you might want to just store a JSON-blob (or something similar) instead. Another option is to store an "id"/key to a different redis object as the value of the map key, but that requires multiple calls to the server to get the full object.
如果你真的需要嵌套结构,你可能只想存储一个 JSON-blob(或类似的东西)。另一种选择是将“id”/键作为映射键的值存储到不同的 redis 对象,但这需要多次调用服务器才能获取完整对象。
回答by fruitJuice
You can just store your structure as is and do an 'eval' to convert from String to Object:
您可以按原样存储结构并执行“eval”以从字符串转换为对象:
images= [{'type':'big', 'url':'....'},
{'type':'big', 'url':'....'},
{'type':'big', 'url':'....'}]
redis = Redis()
redis.hset('photo:1', 'images', images)
i = eval(redis.hget('photo:1', 'images'))
print type(i) #type of i should be list instead of string now
回答by Kyrylo Perevozchikov
Actually, you can store python objects in redis using the built-in module pickle.
实际上,您可以使用内置模块pickle在 redis 中存储 python 对象。
Here is example.
这是示例。
import pickle
import redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
obj = ExampleObject()
pickled_object = pickle.dumps(obj)
r.set('some_key', pickled_object)
unpacked_object = pickle.loads(r.get('some_key'))
obj == unpacked_object
回答by Doug T.
I created a library, SubRedis, which lets you create much more complex structures/hierarchies in redis. If you give it a redis instance and a prefix, it gives you a nearly fully capable and independent redis instance.
我创建了一个库SubRedis,它允许您在 redis 中创建更复杂的结构/层次结构。如果你给它一个 redis 实例和一个前缀,它会给你一个几乎完全有能力和独立的 redis 实例。
redis = Redis()
photoRedis = SubRedis("photo:%s" % photoId, redis)
photoRedis.hmset('image0', images[0])
photoRedis.hmset('image1', images[1])
...
SubRedis just ends up prepending the string passed into it as a prefix onto the flat redis data structure. I find this to be a convenient wrapper for a pattern I end up doing a lot in redis -- prepending some id to nest some data.
SubRedis 最终只是将传入的字符串作为前缀添加到平面 redis 数据结构中。我发现这对于我最终在 redis 中做了很多事情的模式来说是一个方便的包装器——预先添加一些 id 来嵌套一些数据。
回答by CivFan
JSON Example:
JSON 示例:
import json
import redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
images= [
{'type':'big', 'url':'....'},
{'type':'big', 'url':'....'},
{'type':'big', 'url':'....'},
]
json_images = json.dumps(images)
r.set('images', json_images)
unpacked_images = json.loads(r.get('images'))
images == unpacked_images
python 3:
蟒蛇3:
unpacked_images = json.loads(r.get('images').decode('utf-8'))
images == unpacked_images
回答by Seperman
You can use RedisWorkslibrary.
你可以使用RedisWorks图书馆。
pip install redisworks
pip install redisworks
>>> from redisworks import Root
>>> root = Root()
>>> root.something = {1:"a", "b": {2: 2}} # saves it as Hash
>>> print(root.something) # loads it from Redis
{'b': {2: 2}, 1: 'a'}
>>> root.something['b'][2]
2
It converts python types to Redis types and vice-versa.
它将 python 类型转换为 Redis 类型,反之亦然。
>>> root.sides = [10, [1, 2]] # saves it as list in Redis.
>>> print(root.sides) # loads it from Redis
[10, [1, 2]]
>>> type(root.sides[1])
<class 'list'>
Disclaimer: I wrote the library. Here is the code: https://github.com/seperman/redisworks
免责声明:我编写了库。这是代码:https: //github.com/seperman/redisworks
回答by Curtis Yallop
Here is a simple wrapper around Redis which pickles/unpickles data structures:
这是一个围绕 Redis 的简单包装器,它腌制/取消腌制数据结构:
from redis import Redis
from collections import MutableMapping
from pickle import loads, dumps
class RedisStore(MutableMapping):
def __init__(self, engine):
self._store = Redis.from_url(engine)
def __getitem__(self, key):
return loads(self._store[dumps(key)])
def __setitem__(self, key, value):
self._store[dumps(key)] = dumps(value)
def __delitem__(self, key):
del self._store[dumps(key)]
def __iter__(self):
return iter(self.keys())
def __len__(self):
return len(self._store.keys())
def keys(self):
return [loads(x) for x in self._store.keys()]
def clear(self):
self._store.flushdb()
d = RedisStore('redis://localhost:6379/0')
d['a'] = {'b': 1, 'c': 10}
print repr(d.items())
# this will not work: (it updates a temporary copy and not the real data)
d['a']['b'] = 2
print repr(d.items())
# this is how to update sub-structures:
t = d['a']
t['b'] = 2
d['a'] = t
print repr(d.items())
del d['a']
# Here is another way to implement dict-of-dict eg d['a']['b']
d[('a', 'b')] = 1
d[('a', 'b')] = 2
print repr(d.items())
# Hopefully you do not need the equivalent of d['a']
print repr([{x[0][1]: x[1]} for x in d.items() if x[0][0] == 'a'])
del d[('a', 'b')]
del d[('a', 'c')]
If you prefer plaintext-readable data in redis (pickle stores a binary version of it), you can replace pickle.dumps with repr and pickle.loads with ast.literal_eval. For json, use json.dumps and json.loads.
如果您更喜欢 redis 中的纯文本可读数据(pickle 存储它的二进制版本),您可以将 pickle.dumps 替换为 repr,将 pickle.loads 替换为 ast.literal_eval。对于 json,使用 json.dumps 和 json.loads。
If you always use keys which are a simple string, you can remove the pickling from the key.
如果您总是使用简单字符串的键,则可以从键中删除酸洗。
回答by Vetal Latyshev
You can use RedisJSONfrom RedisLabs with client for python. It's supported the nested data structure. Very useful for tasks like this.
您可以将RedisLabs 中的 RedisJSON 与python 客户端一起使用。它支持嵌套数据结构。对于这样的任务非常有用。
Some code from the example:
示例中的一些代码:
# Set the key `obj` to some object
obj = {
'answer': 42,
'arr': [None, True, 3.14],
'truth': {
'coord': 'out there'
}
}
rj.jsonset('obj', Path.rootPath(), obj)
# Get something
print 'Is there anybody... {}?'.format(
rj.jsonget('obj', Path('.truth.coord'))
)

