【Python 3这件小事】3.字符串
3.1 概述
在Python 3,所有的字符串都是使用Unicode编码的字符序列。不再存在以UTF-8或者CP-1252编码的情况。
内置函数len()
可返回字符串的长度,即字符的个数。这与获得列表,元组,集合或者字典的长度的函数是同一个。Python中,字符串可以想像成由字符组成的元组。
与取得列表中的元素一样,也可以通过下标记号取得字符串中的某个字符。
Python字符串可以通过单引号('
)或者双引号("
)来定义。
3.2 格式化字符串
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()
方法的参数替换。
3.2.1 复合字段名
在前一个例子中,替换字段只是简单的整数,这是最简单的用法。整型替换字段被当做传给format()
方法的参数列表的位置索引。即,{0}
会被第一个参数替换(在此例中即username),{1}
被第二个参数替换(password)。
>>> 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'
这一句看上去有些复杂,其实不是这样的。{0}
代表传递给format()
方法的第一个参数,即si_suffixes。注意si_suffixes是一个列表。所以{0[0]}
指代si_suffixes的第一个元素,即'KB'
。同时,{0[1]}
指代该列表的第二个元素,即:'MB'
。大括号以外的内容 — 包括1000
,等号,还有空格等 — 则按原样输出。语句最后返回字符串为'1000KB = 1MB'
。
这个例子说明格式说明符可以通过利用(类似)Python的语法访问到对象的元素或属性。这就叫做复合字段名(compound field names)。以下复合字段名都是“有效的”。
- 使用列表作为参数,并且通过下标索引来访问其元素(跟上一例类似)
- 使用字典作为参数,并且通过键来访问其值
- 使用模块作为参数,并且通过名字来访问其变量及函数
- 使用类的实例作为参数,并且通过名字来访问其方法和属性
- 以上方法的任意组合
3.2.2 格式说明符
if size < multiple: return '{0:.1f} {1}'.format(size, suffix)
1}
会被传递给format()
方法的第二个参数替换,即suffix。但是{0:.1f}
是什么意思呢?它其实包含了两方面的内容:{0}
你已经能理解,:.1f
则不一定了。第二部分(包括冒号及其后边的部分)即格式说明符(format specifier),它进一步定义了被替换的变量应该如何被格式化。
在替换域中,冒号(:
)标示格式说明符的开始。“.1
”的意思是四舍五入到保留一们小数点。“f
”的意思是定点数(与指数标记法或者其他10进制数表示方法相对应)。
3.3 其他常用字符串方法
除了格式化,关于字符串还有许多其他实用的使用技巧。
>>> 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
1.我们可以在Python的交互式shell里输入多行(multiline)字符串。一旦我们以三个引号标记多行字符串的开始,按ENTER键,Python shell会提示你继续这个字符串的输入。连续输入三个结束引号以终止该字符串的输入,再敲ENTER键则会执行该条命令(在当前例子中,把这个字符串赋给变量s)。
2.splitlines()
方法:以多行字符串作为输入,返回一个由字符串组成的列表,列表的元素即原来的单行字符串。请注意,每行行末的回车符没有被包括进去。
3.lower()
方法:把整个字符串转换成小写的。(类似地,upper()
方法执行大写化转换操作。)
4.count()
方法:对串中的指定的子串进行计数。是的,在那一句中确实出现了6个字母“f”。
3.4 String & 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
笔记:
1. 使用“byte字面值”语法b''
来定义bytes
对象。byte字面值里的每个字节可以是ascii字符或者是从\x00
到\xff
编码了的16进制数。
2. 跟列表和字符串一样,我们可以通过内置函数len()
来获得bytes
对象的长度
3. 一如列表和字符串,可以使用下标记号来获取bytes
对象中的单个字节。对字符串做这种操作获得的元素仍为字符串,而对bytes
对象做这种操作的返回值则为整数。确切地说,是0–255之间的整数。
4. 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
对象上。
有一点不同的就是,我们可以使用下标标记给bytearray
对象的某个字节赋值。并且,这个值必须是0–255之间的一个整数。
我们决不应该这样混用bytes和strings。
1.不能连接bytes
对象和字符串。他们两种不同的数据类型。
2.也不允许针对字符串中bytes
对象的出现次数进行计数,因为串里面根本没有bytes
。字符串是一系列的字符序列。也许你是想要先把这些字节序列通过某种编码方式进行解码获得字符串,然后对该字符串进行计数?可以,但是需要显式地指明它。Python 3不会隐含地将bytes转换成字符串,或者进行相反的操作。
那么如何进行count操作呢?
s.count(by.decode('ascii'))
所以,这就是字符串与字节数组之间的联系了:bytes
对象有一个decode()
方法,它使用某种字符编码作为参数,然后依照这种编码方式将bytes
对象转换为字符串,对应地,字符串有一个encode()
方法,它也使用某种字符编码作为参数,然后依照它将串转换为bytes
对象。
3.5 编码方式
Python 3会假定我们的源码 — 即.py
文件 — 使用的是utf-8编码方式。Python 2里,.py
文件默认的编码方式为ascii。
如果想使用一种不同的编码方式来保存Python代码,我们可以在每个文件的第一行放置编码声明(encoding declaration)。以下声明定义.py
文件使用windows-1252编码方式:
# -*- coding: windows-1252 -*-
从技术上说,字符编码的重载声明也可以放在第二行,如果第一行被类unix系统中的hash-bang命令占用了。
#!/usr/bin/python3 # -*- coding: windows-1252 -*-