python连接redis有中文_Python-Redis中的编码问题

本文详细介绍了在Python中使用redis时遇到的编码问题,包括键值对的存储类型、如何正确处理str与bytes之间的转换,以及decode_responses参数的作用和使用场景。通过示例展示了在不同设置下对字典存储和取回的影响,强调了合理设置decode_responses的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在写代码的时候,因为redis的编码的问题,debug了一天,最后终于搞清楚了python-redis中遇到的那些坑。在这里记录一下:

python中如何连接redis:

在python中,我们使用python-redis库来连接redis数据库。我们采用如下方式连接redis:

import redis

pool = redis.ConnectionPool(host='localhost', port=6379)

r = redis.Redis(connection_pool=pool)

我们尝试向redis中添加两个键值对:

r.set('bob','123456')

r.set('alice','987654')

print(r.keys())

'''output

[b'alice', b'bob']

'''

我们会发现,打印出的key数组,每个字符串前面加了一个b。在python3.x中,这表示这个字符串是bytes。

如果我们希望判断'bob'是否在数据库中,并打印bob对应的值,通常我们会这样做:

if 'bob' in r.keys():

print(r.get('bob'))

else:

print('No such key!')

print(r.get('bob'))

'''output

No such key!

b'123456'

'''

我们会发现,明明我们已经在redis中存储了('bob','123456')键值,但是我们使用get()方法却无法获取到。这是因为:

在redis中,键和值都是以bytes方式存储的,r.keys()返回键也是bytes形式的。

当我们判断str类型的字符串是否在 bytes类型的列表中时,结果是False

由于r.get()函数实现中会有encode()操作,所以r.get()可以接受bytes形式,也可以接受str形式

例如:

r.flushall()

r.set('bob','123456')

r.set('alice','987654')

for k in r.keys(): # r.get() 可以接受bytes()类型的输入

print(k,r.get(k))

if 'bob'.encode('utf-8') in r.keys():

print(r.get('bob'))

else:

print('No such key!')

k = 'bob'

print("Encode:",k,r.get(k).decode('utf-8')) # r.get()函数也可以直接传入str

'''output

b'alice' b'987654'

b'bob' b'123456'

b'123456'

Encode: bob 123456

'''

总结:

在redis中存储的键值对均为bytes类型

如果我们希望查询某一个str类型的键是否在数据库中,需要使用encode(),将str转换为bytes,看是否在r.keys()中;使用decode将查询出的bytes值转换为str

如果我们总是使用encode和decode来编码-解码键值对,会非常的麻烦。在python中,我们可以通过声明redis连接池的decode_responses字段来对键值对进行默认编码:

import redis

pool = redis.ConnectionPool(host='localhost', port=6379,decode_responses=True)

r = redis.Redis(connection_pool=pool)

r.flushall()

r.set('Monday','Sunny')

r.set('Tuesday','Rainy')

for k in r.keys():

print(k,r.get(k))

'''output

Tuesday Rainy

Monday Sunny

'''

我们发现,当我们声明了decode_responses=True之后,我们从redis中使用get()和keys()获得的键值对就都是str类型的了。

那么我们是不是一直使用decode_responses=True就好了呢?为什么redis要将decode_responses默认设置成False呢?。我们分别在两种情况下进行如下操作:

创建一个dict

使用pickle对dict打包存储到redis中

读取dict,并使用pickle加载

不使用decode_responses

import redis

import pickle

pool = redis.ConnectionPool(host='localhost', port=6379)

r = redis.Redis(connection_pool=pool)

r.flushall() # 清空redis

d = {'bob':'123456789','alice':'987654321'}

r.set('my_dict',pickle.dumps(d))

new_d = pickle.loads(r.get('my_dict'))

print(new_d)

'''output

{'bob': '123456789', 'alice': '987654321'}

'''

使用decode_responses

import redis

import pickle

pool = redis.ConnectionPool(host='localhost', port=6379,decode_responses=True)

r = redis.Redis(connection_pool=pool)

r.flushall() # 清空redis

d = {'bob':'123456789','alice':'987654321'}

r.set('my_dict',pickle.dumps(d))

new_d = pickle.loads(r.get('my_dict'))

print(new_d)

'''output

Traceback (most recent call last):

File "", line 9, in

new_d = pickle.loads(r.get('my_dict'))

File "C:\ProgramData\Anaconda3\lib\site-packages\redis\client.py", line 1264, in get

return self.execute_command('GET', name)

File "C:\ProgramData\Anaconda3\lib\site-packages\redis\client.py", line 775, in execute_command

return self.parse_response(connection, command_name, **options)

File "C:\ProgramData\Anaconda3\lib\site-packages\redis\client.py", line 789, in parse_response

response = connection.read_response()

File "C:\ProgramData\Anaconda3\lib\site-packages\redis\connection.py", line 637, in read_response

response = self._parser.read_response()

File "C:\ProgramData\Anaconda3\lib\site-packages\redis\connection.py", line 332, in read_response

response = self.encoder.decode(response)

File "C:\ProgramData\Anaconda3\lib\site-packages\redis\connection.py", line 133, in decode

value = value.decode(self.encoding, self.encoding_errors)

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte

'''

这是因为,我们使用pickle存储的时候,pickle会将对象dumps成bytes类型的字符串,并且该字符串无法使用utf-8进行decode。由于我们使用了decode_responses, 执行r.get(‘my_dict’)的时候会尝试将pickle dumps的字符串deocde为utf8,所以会抛出异常。

总结:究竟我们什么时候需要使用decode_responses呢?

如果我们redis只是为了存储一些str字符串等键值对,推荐使用decode_responses来避免在代码手动decode

如果在redis使用中,会涉及对象,字典,列表等的存储,不使用decode_responses

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值