我正在尝试阅读字符串在Python中的工作方式,并且在解读各种功能方面遇到了困难。这是我的理解。希望获得关于如何记住这些细微差别的更正和新观点。
首先,我知道Unicode演变为适应世界各地的多种语言和口音。但是python如何存储字符串?
如果我定义s = 'hello'
,则存储字符串s
的编码是什么?是Unicode吗?还是以纯字节存储?在做type(s)
时,我得到的答案是<type 'str'>
。但是,当我执行us = unicode(s)
时,us
的类型为<type 'unicode'>
。 us
是str
类型还是python中实际上有unicode
类型?
此外,我知道要存储空间,我知道我们使用encode()
函数将字符串编码为字节。因此,假设bs = s.encode('utf-8', errors='ignore')
将返回一个字节对象。因此,现在当我将bs
写入文件时,是否应该以{{1}}模式打开文件?我已经看到,如果以wb
模式打开,它将在文件中将字符串存储为w
。
decode()函数的作用是什么?(我知道,这个问题太开放了。)是否像我们将其应用于字节对象,然后将字符串转换为我们选择的编码?还是总是将其转换回Unicode序列?是否可以从以下几行中得出其他见解?
b"<content in s>"
>>> 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 ()函数。但是,此功能对Unicode字符串和常规字节编码字符串的作用有何不同?先谢谢了。
答案 0 :(得分: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中是不可变的,这使解释器可以方便地决定在创建阶段对字符串进行编码的方式。让我们回顾一下上面的数字:
u
和u[1:]
的差,同时u
和u[:-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个字节),并且它是完全不透明的给程序员。唯一必须透明的是字节序列的编码。我们必须告诉解释器如何处理字节。我们应该让他决定字符串对象的内部表示形式。