创建字符串
>>> s = '深入 Python' ①
>>> len(s) ②
9
>>> s[0] ③
'深'
>>> s + ' 3' ④
'深入 Python 3'
① | 为了创建一个字符串,将其用引号包围。Python字符串可以通过单引号(' )或者双引号(" )来定义。 |
② | 内置函数len() 可返回字符串的长度,即字符的个数。这与获得列表,元组,集合或者字典的长度的函数是同一个。Python中,字符串可以想像成由字符组成的元组。 |
③ | Just like getting individual items out of a list, you can get individual characters out of a string using index notation. 与取得列表中的元素一样,也可以通过下标记号取得字符串中的某个字符。 |
④ | 类似列表,可以使用+ 操作符来连接(concatenate)字符串。 |
格式化字符串
Python 3支持把值格式化(format)成字符串。
可以有非常复杂的表达式,最基本的用法是使用单个占位符(placeholder)将一个值插入字符串。
>>> username = 'mark'
>>> password = 'PapayaWhip'
>>> "{0}'s password is {1}".format(username, password) ①
"mark's password is PapayaWhip"
① | 这里包含了很多知识。首先,这里使用了一个字符串字面值的方法调用。字符串也是对象,对象则有其方法。其次,整个表达式返回一个字符串。最后,{0} 和{1} 叫做替换字段(replacement field),他们会被传递给format() 方法的参数替换。 |
复合字段名
>>> import humansize
>>> si_suffixes = humansize.SUFFIXES[1000] ①
>>> si_suffixes
['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
>>> '1000{0[0]} = 1{0[1]}'.format(si_suffixes) ②
'1000KB = 1MB'
① | 不需要调用humansize 模块定义的任何函数我们就可以抓取到其所定义的数据结构:国际单位制(SI, 来自法语Système International)的后缀列表(以1000为进制)。 |
② | 这一句看上去有些复杂,其实不是这样的。{0} 代表传递给format() 方法的第一个参数,即si_suffixes。注意si_suffixes是一个列表。所以{0[0]} 指代si_suffixes的第一个元素,即'KB' 。同时,{0[1]} 指代该列表的第二个元素,即:'MB' 。大括号以外的内容 — 包括1000 ,等号,还有空格等 — 则按原样输出。语句最后返回字符串为'1000KB = 1MB' 。 |
这个例子说明格式说明符可以通过利用(类似)Python的语法访问到对象的元素或属性。
这就叫做复合字段名(compound field names)。以下复合字段名都是“有效的”。
- 使用列表作为参数,并且通过下标索引来访问其元素(跟上一例类似)
- 使用字典作为参数,并且通过键来访问其值
- 使用模块作为参数,并且通过名字来访问其变量及函数
- 使用类的实例作为参数,并且通过名字来访问其方法和属性
- 以上方法的任意组合
>>> import humansize
>>> import sys
>>> '1MB = 1000{0.modules[humansize].SUFFIXES[1000][0]}'.format(sys)
'1MB = 1000KB'
下面是描述它如何工作的:
-
sys
模块保存了当前正在运行的Python实例的信息。由于已经导入了这个模块,因此可以将其作为format()
方法的参数。所以替换域{0}
指代sys
模块。 -
sys.modules
is a dictionary of all the modules that have been imported in this Python instance. The keys are the module names as strings; the values are the module objects themselves. So the replacement field{0.modules}
refers to the dictionary of imported modules.sys.modules
是一个保存当前Python实例中所有已经导入模块的字典。模块的名字作为字典的键;模块自身则是键所对应的值。所以{0.modules}
指代保存当前己被导入模块的字典。 -
sys.modules['humansize']
即刚才导入的humansize
模块。所以替换域{0.modules[humansize]}
指代humansize
模块。请注意以上两句在语法上轻微的不同。在实际的Python代码中,字典sys.modules
的键是字符串类型的;为了引用它们,我们需要在模块名周围放上引号(比如'humansize'
)。但是在使用替换域的时候,我们在省略了字典的键名周围的引号(比如humansize
)。在此,我们引用PEP 3101:字符串格式化高级用法,“解析键名的规则非常简单。如果名字以数字开头,则它被当作数字使用,其他情况则被认为是字符串。” -
sys.modules['humansize'].SUFFIXES
是在humansize
模块的开头定义的一个字典对象。{0.modules[humansize].SUFFIXES}
即指向该字典。 -
sys.modules['humansize'].SUFFIXES[1000]
是一个si(国际单位制)后缀列表:['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
。所以替换域{0.modules[humansize].SUFFIXES[1000]}
指向该列表。 -
sys.modules['humansize'].SUFFIXES[1000][0]
即si后缀列表的第一个元素:'KB'
。因此,整个替换域{0.modules[humansize].SUFFIXES[1000][0]}
最后都被两个字符KB
替换。
if size < multiple:
return '{0:.1f} {1}'.format(size, suffix)
{1}
会被传递给
format()
方法的第二个参数替换,即
suffix
。但是
{0:.1f}
是什么意思呢?它其实包含了两方面的内容:
{0}
你已经能理解,
:.1f
则不一定了。第二部分(包括冒号及其后边的部分)即
格式说明符(format specifier)
,它进一步定义了被替换的变量应该如何被格式化。
格式说明符的允许你使用各种各种实用的方法来修饰被替换的文本,就像C语言中的
printf()
函数一样。我们可以添加使用零填充(zero-padding),衬距(space-padding),对齐字符串(align strings),控制10进制数输出精度,甚至将数字转换成16进制数输出。
在替换域中,冒号(
:
)标示格式说明符的开始。“
.1
”的意思是四舍五入到保留一们小数点。“
f
”的意思是定点数(与指数标记法或者其他10进制数表示方法相对应)。因此,如果给定
size为698.24
,suffix为'GB'
,那么格式化后的字符串将是'698.2 GB'
,因为698.24
被四舍五入到一位小数表示,然后后缀'GB'
再被追加到这个串最后。
其他字符串方法
>>> s = '''Finished files are the re- ①
... sult of years of scientif-
... ic study combined with the
... experience of years.'''
>>> s.splitlines() ②
['Finished files are the re-',
'sult of years of scientif-',
'ic study combined with the',
'experience of years.']
>>> print(s.lower()) ③
finished files are the re-
sult of years of scientif-
ic study combined with the
experience of years.
>>> s.lower().count('f') ④
6
① | 我们可以在Python的交互式shell里输入多行(multiline)字符串。一旦我们以三个引号标记多行字符串的开始,按ENTER键,Python shell会提示你继续这个字符串的输入。连续输入三个结束引号以终止该字符串的输入,再敲ENTER键则会执行该条命令(在当前例子中,把这个字符串赋给变量s)。 |
② |
splitlines() 方法以多行字符串作为输入,返回一个由字符串组成的列表,列表的元素即原来的单行字符串。请注意,每行行末的回车符没有被包括进去。 |
③ |
lower() 方法把整个字符串转换成小写的。(类似地,upper() 方法执行大写化转换操作。) |
④ |
count() 方法对串中的指定的子串进行计数。是的,在那一句中确实出现了6个字母“f”。 |
>>> query = 'user=pilgrim&database=master&password=PapayaWhip'
>>> a_list = query.split('&') ①
>>> a_list
['user=pilgrim', 'database=master', 'password=PapayaWhip']
>>> a_list_of_lists = [v.split('=', 1) for v in a_list] ②
>>> a_list_of_lists
[['user', 'pilgrim'], ['database', 'master'], ['password', 'PapayaWhip']]
>>> a_dict = dict(a_list_of_lists) ③
>>> a_dict
{'password': 'PapayaWhip', 'user': 'pilgrim', 'database': 'master'}
① |
split() 方法使用一个参数,即指定的分隔符,然后根据这个分隔符将串分离成一个字符串列表。此处,分隔符即字符“& ”,它还可以是其他的内容。 |
② | 现在我们有了一个字符串列表,其中的每个串由三部分组成:键,等号和值。我们可以使用列表解析来遍历整个列表,然后利用第一个等号标记将每个字符串再分离成两个子串。(理论上,值也可以包含等号标记,如果执行'key=value=foo'.split('=') ,那么我们会得到一个三元素列表['key', 'value', 'foo'] 。) |
③ | 最后,通过调用dict() 函数Python会把那个包含列表的列表(list-of-lists)转换成字典对象。 |
>>> a_string = 'My alphabet starts where your alphabet ends.'
>>> a_string[3:11] ①
'alphabet'
>>> a_string[3:-3] ②
'alphabet starts where your alphabet en'
>>> a_string[0:2] ③
'My'
>>> a_string[:18] ④
'My alphabet starts'
>>> a_string[18:] ⑤
' where your alphabet ends.'
① | 我们可以通过指定两个索引值来获得原字符串的一个“slice”。该操作的返回值是一个新串,依次包含了从原串中第一个索引位置开始,直到但是不包含第二个索引位置之间的所有字符。 |
② | 就像给列表做分片一样,我们也可以使用负的索引值来分片字符串。 |
③ | 字符串的下标索引是从0开始的,所以a_string[0:2] 会返回原字符串的前两个元素,从a_string[0] 开始,直到但不包括a_string[2] 。 |
④ | 如果省略了第一个索引值,Python会默认它的值为0。所以a_string[:18] 跟a_string[0:18] 的效果是一样的,因为从0开始是被Python默认的。 |
⑤ | 同样地,如果第2个索引值是原字符串的长度,那么我们也可以省略它。所以,在此处a_string[18:] 跟a_string[18:44] 的结果是一样的,因为这个串的刚好有44个字符。这种规则存在某种有趣的对称性。在这个由44个字符组成的串中,a_string[:18] 会返回前18个字符,而a_string[18:] 则会返回除了前18个字符以外字符串的剩余部分。事实上a_string[:n] 总是会返回串的前n个字符,而a_string[n:] 则会返回其余的部分,这与串的长度无关。 |
STRING VS. BYTES
字节 即字节;字符是一种抽象。一个不可变(immutable)的Unicode编码的字符序列叫做 string 。
一串由0到255之间的数字组成的序列叫做bytes对象。
>>> by = b'abcd\x65' ①
>>> by
b'abcde'
>>> type(by) ②
<class 'bytes'>
>>> len(by) ③
5
>>> by += b'\xff' ④
>>> by
b'abcde\xff'
>>> len(by) ⑤
6
>>> by[0] ⑥
97
>>> by[0] = 102 ⑦
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'bytes' object does not support item assignment
① | 使用“byte字面值”语法b'' 来定义bytes 对象。byte字面值里的每个字节可以是ascii字符或者是从\x00 到\xff 编码了的16进制数。 |
② |
bytes 对象的类型是bytes 。 |
③ | 跟列表和字符串一样,我们可以通过内置函数len() 来获得bytes 对象的长度。 |
④ | 使用+ 操作符可以连接bytes 对象。操作的结果是一个新的bytes 对象。 |
⑤ | 连接5个字节的和1个字节的bytes 对象会返回一个6字节的bytes 对象。 |
⑥ | 一如列表和字符串,可以使用下标记号来获取bytes 对象中的单个字节。对字符串做这种操作获得的元素仍为字符串,而对bytes 对象做这种操作的返回值则为整数。确切地说,是0–255之间的整数。 |
⑦ |
bytes 对象是不可变的;我们不可以给单个字节赋上新值。如果需要改变某个字节,可以组合使用字符串的切片和连接操作(效果跟字符串是一样的),或者我们也可以将bytes 对象转换为bytearray 对象。 |
>>> by = b'abcd\x65'
>>> barr = bytearray(by) ①
>>> barr
bytearray(b'abcde')
>>> len(barr) ②
5
>>> barr[0] = 102 ③
>>> barr
bytearray(b'fbcde')
① | 使用内置函数bytearray() 来完成从bytes 对象到可变的bytearray 对象的转换。 |
||||||||||||||||
② | 所有对bytes 对象的操作也可以用在bytearray 对象上。 |
||||||||||||||||
③ |
有一点不同的就是,我们可以使用下标标记给
>>> by = b'd'
>>> a_string = '深入 Python' ①
|