Python - 关于如何在Python中存储和处理字符串的困惑

问题描述 投票:1回答:1

我试图阅读字符串如何在Python中工作,并且很难解读各种功能。这是我的理解。希望得到更正和新的观点,如何记住这些细微差别。

  • 首先,我知道Unicode已经发展到适应世界各地的多种语言和口音。但是python如何存储字符串?如果我定义s = 'hello'字符串s存储的编码是什么?是Unicode吗?或者它以普通字节存储?在做type(s)我得到了<type 'str'>的答案。但是,当我做us = unicode(s)时,us属于<type 'unicode'>usstr类型还是在python中实际上有unicode类型?
  • 另外,我知道要存储空间,我知道我们使用encode()函数将字符串编码为字节。所以假设bs = s.encode('utf-8', errors='ignore')将返回一个字节对象。所以,现在当我将bs写入文件时,我应该以wb模式打开文件吗?我已经看到,如果在w模式下打开,它会将文件中的字符串存储为b"<content in s>"
  • decode()函数做了什么?(我知道,问题太开放了。)是不是,我们将它应用于一个字节对象,这会将字符串转换为我们选择的编码?或者它总是将其转换回Unicode序列?可以从以下几行得出任何其他见解吗?
>>> s = 'hello'
>>> bobj = bytes(s, 'utf-8')
>>> bobj
'hello'
>>> type(bobj)
<type 'str'>
>>> bobj.decode('ascii')
u'hello'
>>> us = bobj.decode('ascii')
>>> type(us)
<type 'str'>
  • str(object)如何运作?我读到它会尝试在对象描述中执行str()函数。但是这个函数对Unicode字符串和常规字节编码字符串有何不同?

提前致谢。

python unicode encode
1个回答
2
投票

重要:下面描述了python3行为。虽然python2有一些概念上的相似之处,但暴露的行为会有所不同。

简而言之:由于unicode支持python3中的字符串对象是更高级别的抽象。解释器如何在内存中表示它。因此,当涉及序列化(例如,将字符串的文本表示写入文件)时,需要首先使用指定的编码(例如UTF-8)将其显式编码为字节序列。对于字节到字符串的转换,即解码,情况也是如此。在python2中,使用unicode类可以实现相同的行为,而str则是bytes的同义词。

虽然它不是您问题的直接答案,但请看一下这些示例:

import sys

e = ''
print(len(e))            # 0
print(sys.getsizeof(e))  # 49

a = 'hello'
print(len(a))            # 5
print(sys.getsizeof(a))  # 54

u = 'hello平仮名'
print(len(u))                 # 8
print(sys.getsizeof(u))       # 90
print(len(u[1:]))             # 7
print(sys.getsizeof(u[1:]))   # 88
print(len(u[:-1]))            # 7
print(sys.getsizeof(u[:-1]))  # 88
print(len(u[:-2]))            # 6
print(sys.getsizeof(u[:-2]))  # 86
print(len(u[:-3]))            # 5
print(sys.getsizeof(u[:-3]))  # 54
print(len(u[:-4]))            # 4
print(sys.getsizeof(u[:-4]))  # 53

j = 'hello😋😋😋'
print(len(j))                 # 8
print(sys.getsizeof(j))       # 108
print(len(j[:-1]))            # 7
print(sys.getsizeof(j[:-1]))  # 104
print(len(j[:-2]))            # 6
print(sys.getsizeof(j[:-2]))  # 100

字符串在Python中是不可变的,这使得解释器有一个优势来决定字符串在创建阶段将被编码的方式。我们来看看上面的数字:

  • 空字符串对象的开销为49字节。
  • 长度为5的ASCII符号的字符串大小为49 + 5。编码每个符号使用1个字节。
  • 具有混合(ASCII +非ASCII)符号的字符串具有更高的内存占用,即使长度仍为8。
  • uu[1:]的差异,同时uu[:-1]的差异是90 - 88 = 2 bytes。即编码每个符号使用2个字节。即使字符串的前缀可以用每个符号1个字节进行编码。这为我们提供了对字符串进行恒定时间索引操作的巨大优势,但我们需要额外的内存开销。
  • 字符串j的内存占用率更高。这只是因为我们不能使用每个符号2个字节来编码其中的所有符号,因此解释器现在每个符号使用4个字节。

好的,继续检查行为。我们已经知道,解释器以符号方式存储偶数个字节的字符串,以便通过索引为我们提供O(1)访问。但是,我们也知道UTF-8使用符号的可变长度表示。让我们证明一下:

j = 'hello😋😋😋'
b = j.encode('utf8')  # b'hello\xf0\x9f\x98\x8b\xf0\x9f\x98\x8b\xf0\x9f\x98\x8b'    
print(len(b))  # 17

因此,我们可以看到,前5个字符使用每个符号1个字节进行编码,而其余3个符号使用每个符号使用(17 - 5)/3 = 4字节进行编码。这也解释了为什么python在引擎盖下每个符号表示使用4个字节。

另一种方式,当我们有一个字节序列和decode它到一个字符串时,解释器将决定内部字符串表示(每个符号1,2或4个字节),它对程序员完全不透明。唯一必须透明的是字节序列的编码。我们必须告诉解释器如何处理字节。虽然我们应该让他决定字符串对象的内部表示。

© www.soinside.com 2019 - 2024. All rights reserved.