Python str和unicode之间的区别:为什么Redis在传递unicode时返回二进制数据?

Python str和unicode之间的区别:为什么Redis在传递unicode时返回二进制数据?,python,string,unicode,utf-8,redis,Python,String,Unicode,Utf 8,Redis,关于数据类型str和unicode之间的区别,我仍然对以下内容感到困惑 在Block 1中,我们看到城市的类型是unicode,正如我们所期望的那样 然而在区块2中,经过一次磁盘往返(redis)之后,城市的类型是str(表示方式不同) 将utf-8存储在磁盘上,读取unicode,然后回写utf-8的方法在某些地方失败了 为什么第二个实例是type(city)str而不是unicode 同样重要的是,这重要吗?您是否关心您的变量是unicode还是str,还是只要代码“做正确的事情”,您就忽略

关于数据类型
str
unicode
之间的区别,我仍然对以下内容感到困惑

在Block 1中,我们看到城市的类型是unicode,正如我们所期望的那样

然而在区块2中,经过一次磁盘往返(redis)之后,城市的类型是
str
(表示方式不同)

utf-8
存储在磁盘上,读取
unicode
,然后回写
utf-8
的方法在某些地方失败了

为什么第二个实例是
type(city)
str
而不是
unicode

同样重要的是,这重要吗?您是否关心您的变量是
unicode
还是
str
,还是只要代码“做正确的事情”,您就忽略了差异

#-*-编码:utf-8-*-
#第一区
城市=u'Düsseldorf'
打印城市、类型(城市)、报告(城市)
#杜塞尔多夫
#第2区
导入redis
r_server=redis.redis('localhost'))
r_server.set('city',city)
city=r\u server.get('city')
打印城市、类型(城市)、报告(城市)
#杜塞尔多夫'D\xc3\xbcsseldorf'
教条? 使用字符集和编码并不是教条式的——这是必要的。 希望您已经读了足够多的书来理解为什么我们有这么多的字符集在使用。Unicode显然是前进的方向(映射所有字符),但如何将Unicode字符从一台机器传输到另一台机器,或将其保存到磁盘

我们可以使用Unicode点值,但由于Unicode点值实际上是32位,因此每个字符都需要保存/传输为整个32位(也称为UTF-32)
a
将被编码为
0x00000061
——仅仅一个字符就浪费了很多位。在处理大部分ASCII码时,UTF-16的浪费稍微少一些,但UTF-8是使用最少比特数的最佳折衷方案

在代码中使用解码的Unicode显然可以使开发者免于考虑编码的复杂性,比如一个字符等于多少字节。

解决 Redis客户端 正如@J.F.Sebastian所建议的,redis py驱动程序在
redis
连接
类上包括一个
decode\u responses
选项。当设置为
True
时,客户端将使用
encoding
选项对响应进行解码。默认情况下
编码=utf-8

例如

然后,您可以与它正常交互,除了可以传递一个
编码
参数来更改字符串的解码方式。如果未设置
编码
,则此代码将假定为
utf-8

例如


正如J.F.Sebastian所说,redis py API通过在redis.redis类的init方法中设置
decode\u response=True
来支持对unicode的解码响应。

这意味着redis API返回的是二进制
str
,而不是unicode对象。没有什么必然的错误,这只是API所做的。可能的重复应该看Ned Batchelder在@mgilson上的演讲。这就是我指的教条。(我并不是轻蔑地使用这个词,只是想表明,在一个人完全理解如何“统一编码”自己的代码之前,提炼他的建议是有用的。)@Calaf——啊,你这么做了。对不起,我没有看到链接。在这种情况下,您可能希望在server.set时解码为字节,然后对结果进行编码:
r_server.set('city',city.decode('utf-8');city=r_server.get('city').encode('utf-8')
1-一个字节与一个Unicode码点一样是一个抽象(考虑系统上任何一个字节不是八位字节的网络API)。操作系统可以为文件、网络等提供Unicode API(Windows在许多情况下都会这样做)。Redis Python绑定以二进制blob的形式返回文本,这无疑是一个缺陷。2-
sys.maxunicode.bit_length()
不在此处,例如,Python 3.3+使用灵活的内部表示法。或者更简单:库可以提供Unicode API,同时对特定情况下最有用的任何表示进行内部编码/解码(正如您的
UnicodeDis
所做的),传递
decode\u responses=True
可以代替UnicodeDis中的手动编码/解码。啊,谢谢@J.F.Sebastian。我到处寻找这样一种财产。我所说的“教条”是指“一点点有用的、容易记住的知识”,而不是像你所解释的那样,不太准确或不必要的知识抱歉@calaf,我理解这里定义的“教条”:。如果教条只是一点点有用就好了:)
# -*- coding: utf-8 -*-

# Block 1
city = u'Düsseldorf'
print city, type(city), repr(city)
# Düsseldorf <type 'unicode'> u'D\xfcsseldorf'

# Block 2
import redis
r_server = redis.Redis('localhost')
r_server.set('city', city)
city = r_server.get('city')
print city, type(city), repr(city)
# Düsseldorf <type 'str'> 'D\xc3\xbcsseldorf'
r_server = redis.Redis('localhost', decode_responses=True)
city = r_server.get('city')
# city = <type 'unicode'>
class UnicodeRedis(redis.Redis):

    def __init__(self, *args, **kwargs):
        if "encoding" in kwargs:
            self.encoding = kwargs["encoding"]
        else:
            self.encoding = "utf-8"
        super(UnicodeRedis, self).__init__(*args, **kwargs)

    def get(self, *args, **kwargs):
        result = super(UnicodeRedis, self).get(*args, **kwargs)
        if isinstance(result, str):
            return result.decode(self.encoding)
        else:
            return result
r_server = UnicodeRedis('localhost')
city = r_server.get('city')