关于数据类型str
和unicode
之间的区别two questions之后,我仍对以下内容感到困惑。
在第1区,我们看到城市的类型为unicode
,正如我们所料。
然而在第2区中,在通过磁盘往返(redis)之后,城市的类型为str
(且表示形式不同)。
在磁盘上存储utf-8
的{{3}},读入unicode
,并在utf-8
中回写在某处失败。
为什么type(city)
str
而不是unicode
的第二个实例?
同样重要的是,这有关系吗?你是否关心你的变量是unicode
还是str
,或者只要代码“做正确的事情”,你是否忘记了差异?
# -*- 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'
答案 0 :(得分:11)
使用字符集和编码并不是教条主义 - 这是必要的。 希望您已经阅读了足以理解为什么我们使用了这么多字符集。 Unicode显然是前进的方向(映射了所有字符),但是如何将Unicode字符从一台机器传输到另一台机器,或者将其保存到磁盘?
我们可以使用Unicode点值,但由于Unicode点实际上是32位,因此需要将每个字符保存/传输为整个32位(也称为UTF-32)。 a
将被编码为0x00000061
- 这只是一个字符的浪费。在处理大多数ASCII时,UTF-16的浪费要少一些,但UTF-8是使用最少量位的最佳折衷方案。
在代码中使用解码的Unicode显然使开发人员不必考虑编码的复杂性,例如与字符相等的字节数。
正如@ J.F.Sebastian所建议的那样,redis-py驱动程序在decode_responses
和Redis
类中包含Connection
选项。设置为True
时,客户端将使用encoding
选项解码响应。默认情况下为encoding = utf-8
。
E.g。
r_server = redis.Redis('localhost', decode_responses=True)
city = r_server.get('city')
# city = <type 'unicode'>
发现decode_responses
后不再需要。
<击> 撞击>
<击>似乎Redis驱动程序相当简单 - 如果你发送一个Unicode,它会将它转换为默认编码(大多数情况下是UTF-8)。在响应时,Redis不知道编码,因此返回str
以供您解密。
因此,如果在发送到Redis之前将字符串编码为UTF-8并在响应时解码为UTF-8会更安全。其他DB驱动程序更高级,因此接收并返回Unicodes。
但是,当然,您不应该使用.encode()
和.decode()
来编写代码。常见的方法是形成“Unicode三明治”,以便外部数据在输入时解码为Unicode并在输出上进行编码。那么这对你有什么用呢? 包装Redis驱动程序,以便它返回您想要的内容,从而将解码推回到代码的外围。
例如,它应该如下:
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
然后您可以正常与它进行交互,除了您可以传递更改字符串解码方式的encoding
参数。如果您未设置encoding
,则此代码将采用utf-8
。
E.g。
r_server = UnicodeRedis('localhost')
city = r_server.get('city')
击> <击> 撞击>
答案 1 :(得分:0)
正如J.F. Sebastian所说,redis-py API支持通过在redis.Redis类的 init 方法中设置decode_response=True
来解码对unicode的响应。