第三章:使用字符串
1:基本字符串操作:所有标准的序列操作(索引、分片、乘法、判断成员资格、求长度、取最小值和最大值)对字符串同样适用。但记住:字符串是不可变的
2:字符串格式化:精简版
使用字符串格式化操作符即百分号%来实现。注意:%也可以用作模运算(求余)操作符
>>> format = "Hello,%s. %s enough for ya?" >>> values = ('World', 'Hot') >>> print(format % values) Hello,World. Hot enough for ya?
#等同:"Hello,%s. %s enough for ya?" % ('World','Hot')
注意:如果要使用列表或者其他序列代替元组,那么序列就会被解释为一个值。只有元组和字典可以格式化一个以上的值
格式化字符串的%s部分称为转换说明符(conversion specifier),它们标记了需要插入转换值的位置。s表示值会被格式化为字符串——如果不是字符串,则会用str将其转换为字符串。
注意:如果要在格式化字符串里包含百分号,那么必须使用%%,这样python就不会将百分号误认为是转换说明符了
如果要格式化实数(浮点数),可以使用f说明符类型,同时提供所需要的精度:一个句点加上希望保留的小数位数。因为格式化说明符总是以表示类型的字符结束,所以精度应该放在类型字符前面:
>>> format="Pi with three decimals: %.3f" >>> from math import pi >>> print(format % pi) Pi with three decimals: 3.142
string模块提供另外一种格式化值的方法:模板字符串。它的工作方式类似于很多UNIX Shell里的变量替换。如下所示,substitute这个模板方法会用传递进来的关键字参数foo替换字符串中的$foo
>>> from string import Template >>> s = Template('$x, glorious $x!') >>> s.substitute(x='slurm') 'slurm, glorious slurm!'
如果替换字段是单词的一部分,那么参数名就必须用括号括起来,从而准确指明结尾:
>>> s = Template("It's ${x}tastic") >>> s.substitute(x='slurm') "It's slurmtastic"
可以使用$$插入美元符号:
>>> s=Template("Make $$ selling $x!") >>> s.substitute(x='slurm') 'Make $ selling slurm!'
除了关键字参数外,还可以使用字典变量提供值/名称对
>>> s=Template('A $thing must never $action') >>> d={} >>> d['thing']='gentleman' >>> d['action']='show his socks' >>> s.substitute(d) 'A gentleman must never show his socks'
方法 safe_substitute 不会因为缺少值或者不正确使用$字符而出错
3:字符串格式化:完整版——格式化操作符的右操作数可以是任何东西,如果是元组或者映射类型(如字典),那么字符串格式化将会有所不同。
如果右操作数是元组的话,则其中的每一个元素都会被单独格式化,每个值都需要一个对应的转换说明符。
说明:如果需要转换的元组作为转换表达式的一部分存在,那么必须将它用圆括号括起来,以避免出错
>>> '%s plus %s equals %s' % (1,1,2) #必须要有括号,否则出错 '1 plus 1 equals 2'
基本的转换说明符,注意,这些项的顺序是至关重要的:
(1) %字符:标记转换说明符的开始
(2) 转换标记(可选):-表示左对齐;+表示在转换值之前要加上正负号;""(空白字符)表示正数之前保留空格;0表示转换值若位数不够则用0填充
(3) 最小字段宽度(可选):转换后的字符串至少应该具有该值指定的宽度,如果是*,则宽度会从值元组中读出
(4) 点(.)后跟精度值(可选):如果转换的是实数,精度值就表示出现在小数点后的位数。如果转换的是字符串,那么该数字就表示最大字段宽度。如果是*,那么精度将会从元组中读出
(5) 转换类型:
(1) 简单转换
>>> 'Price of eggs: $%d' % 42 #十进制整数 'Price of eggs: $42' >>> 'Hexadecimal price of eggs: %x' % 42 #十六进制 'Hexadecimal price of eggs: 2a' >>> from math import pi >>> 'Pi: %f...' % pi #十进制浮点数 'Pi: 3.141593...' >>> 'Very inexact estimate of pi: %i' % pi #十进制整数 'Very inexact estimate of pi: 3' >>> 'Using str: %s' % 42 #字符串(使用str转换任意python对象) 'Using str: 42' >>> 'Using repr: %r' % 42 #字符串(使用repr转换任意python对象) 'Using repr: 42'
(2) 字段宽度和精度——这两个参数都是整数,通过点号分隔(字段宽度.精度)。虽然两个都是可选参数,但如果只给出精度,就必须包含点号
>>> '%10f' % pi #字段宽度 10 ' 3.141593' >>> '%10.2f' % pi #字段宽度10,精度2 ' 3.14' >>> '%.2f' % pi #精度 2 '3.14' >>> '%.5s' % 'Guido van Rossum' #精度对于字符串转换来说,是转换后的值所能包含的最大字符个数 'Guido'
可以使用*(星号)作为自动宽度或精度(或两者都使用*),此时数值会从元组参数中读出:
>>> '%.*s' % (5, 'Guido van Rossum') 'Guido'
(3) 符号、对齐和0填充——在字段宽度和精度值之前还可以放置一个”标表“,该标表可以是零、加号、减号或空格。零表示数字将会用0进行填充。
>>> '%010.2f' % pi '0000003.14'
注意:在010中开头的那个0并不意味着字段宽度说明符为八进制数,它只是个普通的python数值。010表示字段宽度为10,并且用0进行填充空位。
使用减号(-)左对齐数值:
>>> '%-10.2f' % pi '3.14 '
而空白("")意味着在正数前加上空格。这在需要对齐正负数时会很有用:
>>> print(('% 5d' % 10) + '\n' + ('% 5d' % -10)) 10 -10
加号(+),它表示不管是正数还是负数都标示出符号(同样是在对齐时很有用):
>>> print(('%+5d' % 10) + '\n' + ('%+5d' % -10)) +10 -10
字符串格式化示例:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#使用给定的宽度打印格式化后的价格列表 width = int(input('Please enter width: ')) price_width = 10 item_width = width - price_width header_format = '%-*s%*s' #负号表示左对齐 format = '%-*s%*.2f' print('=' * width) print(header_format % (item_width, 'Item', price_width, 'Price')) print('-' * width) print(format % (item_width, 'Apples', price_width, 0.4)) print(format % (item_width, 'Pears', price_width, 0.5)) print(format % (item_width, 'Cantaloupes', price_width, 1.92)) print(format % (item_width, 'Dried Apricots (16 oz.)', price_width, 8)) print(format % (item_width, 'Prunes (4 lbs.)', price_width, 12)) print('=' * width)
4:字符串方法——字符串的方法比列表还多,因为字符串从string模块中”继承“了很多方法
尽管字符串方法完全来源于string模块,但这个模块还包括一些不能作为字符串方法是用的常量和函数。如 maketrans、translate 方法。常用字符串常量:
string.digits:包含数字0~9的字符串
string.letters:包含所有字母(大写或小写)的字符串
string.lowercase:包含所有小写字母的字符串
string.printable:包含所有可打印字符的字符串
string.punctuation:包含所有标点的字符串
string.uppercase:包含所有大写字母的字符串
注意:字母字符串常量(如string.letters)与地区有关(其值取决于Python所配置的语言)。如果可以确定自己使用的ASCII,则可在变量中使用ascii_前缀,如:string.asscii_letters
>>> from string import digits >>> digits '0123456789' >>> import string >>> string.digits '0123456789'
1)find 方法——可以在一个较长的字符串中查找子字符串。它返回子串所在位置的最左端索引。如果没有找到返回-1
>>> 'With a moo-moo here, and a moo-moo there'.find('moo') 7 >>> title="Monty Python's Flying Circus" >>> title.find('Monty') 0 >>> title.find('Python') 6 >>> title.find('Zirquss') -1
注意:字符串的find 方法并不返回布尔值。如果返回0,则证明索引0位置找到了子串
这个方法还可以接受可选的起始点和结束点参数:
>>> subject = '$$$ Get rich now!!! $$$' >>> subject.find('$$$') 0 >>> subject.find('$$$', 1) #只提供起始点 20 >>> subject.find('!!!',0,16) #提供起始点和结束点 -1
2)join 方法——它是split 方法的逆方法,用来在队列中添加元素(注意:需要添加的队列元素都必须是字符串):
>>> seq=[1,2,3,4,5] >>> seperator='+' >>> seperator.join(seq) #会报错,因为seq中的元素不是字符串 >>> seq=['1','2','3','4','5'] >>> seperator='+' >>> seperator.join(seq) #不能seq.join(seperator),因为seq是列表而不是字符串,没有join 方法 '1+2+3+4+5'
3)lower 方法——返回字符串的小写字母版
>>> name = 'Gumby' >>> names = ['gumby', 'smith', 'jones'] >>> if name.lower() in names : print('Fount it!')
与lower 方法相关的是title方法,它会将字符串转换为标题——也就是所有单词的首字母大写,而其他字母小写。另外string模块中也有个capwords函数:
>>> "that's all folks".title() "That'S All Folks" >>> import string >>> string.capwords("that's all folks") "That's All Folks"
4)replace 方法 —— 返回某字符串的所有匹配项均被替换之后得到的字符串
>>> 'This is a test'.replace('is', 'eez') 'Theez eez a test'
5)split 方法 —— join方法的逆方法,用来将字符串分隔成序列。如果不提供任何分隔符,程序会把所有空格作为分隔符(空格、制表、换行等)
>>> '1+2+3+4+5'.split('+') ['1', '2', '3', '4', '5'] >>> 'Using the default'.split() ['Using', 'the', 'default']
6)strip 方法 —— 返回去除两侧(不包括内部)空格的字符串
>>> ' internal withespace is kept '.strip() 'internal withespace is kept'
也可以指定要去除的字符,将它们列为参数即可
>>> ' *** SPAM * for * everyone!!! *** '.strip(' *!') 'SPAM * for * everyone'
7)translate 方法 —— 和replace 方法一样,可以替换字符串中的某些部分,但是与前者不同的是,translate方法只处理单个字符。它的优势在于可以同时进行多个替换,有时候比replace效率高得多。
在使用translate 转换之前,需要先完成一张转换表。转换表中是以某字符替换某字符的对应关系。可以使用string 模块里面的maketrans 函数(也可以自己写转换表)。maketrans 函数接受两个参数:两个等长的字符串,表示第一个字符串中的每个字符都用第二个字符串中相同位置的字符替换:
>>> a = 'Hello, World!' >>> t = a.maketrans('l','a') >>> a.translate(t) 'Heaao, Worad!'
5:小结
字符串格式化:求模操作符(%)可以用来将其他值转换为包含转换标志的字符串,如%s。它还能用来对值进行不同方式的格式化,包括左右对齐、设定字段宽度以及精度值,增加符号(正负号)或者左填充数字0等
字符串方法:字符串有很多方法,有些很有用(如split和join),有些则很少用(如:istitle和capitalize)
第四章:字典:当索引不好用时
如果想将值分组到一个结构中,并且通过编号对其进行引用,列表(list)就能派上用场。本章学习一种通过名字引用值的数据结构:这种结构类型称为映射(mapping)。字典是python中唯一内建的映射类型。字典中的值并没有特殊的顺序,但是都存储在一个特定的键(Key)里。键可以是数字、字符串甚至是元组。
1:字典的创建与使用
1)创建——字典由多个键及其对应的值构成的对 组成(键/值对 也称为 项),键和值之间用冒号(:)隔开,项之间用逗号(,)隔开,整个字典用大括号括起来。
phonebook={'Alice':'2341','Beth':'9102','Cecil':'3258'}
也可以使用 dict 函数(并非真正函数,实际是一个类型),通过其他映射(比如其他字典)或者(键,值)这样的序列对 建立字典
>>> items = [('name','Gumby'),('age',42)] >>> d = dict(items) >>> d {'age': 42, 'name': 'Gumby'} >>> d['name'] 'Gumby'
dict 函数也可以通过关键字参数来创建字典,这是dict 函数最有用的功能
>>> dic = dict(name='Aaron', age=24) >>> dic {'age': 24, 'name': 'Aaron'}
2)基本字典操作
字典的基本行为在很多方面与序列(sequence)类似:
A:len(d)返回d中项(键值对)的数量
B:d[k]返回关联到键k上的值
C:d[k]=v将值v关联到键k上
D:del d[k] 删除键为k的项
E:k in d 检查d中是否含有键为k的项
区别:
A:键类型:字典的键不一定是整型数据,也可能是其他不可变类型,如浮点型(实型)、字符串或元组(这是字典最强大的地方)
B:自动添加:即使那个键起初在字典中并不存在,也可以为它分配一个值,这样字典就会建立新的项。而(在不使用append方法或者类似操作的情况下)不能将值关联到列表范围之外的索引上。
C:成员资格:表达式 k in d 查找的是键而不是值。表达式 v in l(list列表)则用来查找值,而不是索引。
提示:在字典中检查键的成员资格比在列表中检查值的成员资格更高效,数据结构规模越大,两者效率差距越明显
>>> x = [] >>> x[42] = 'Foobar' #引发异常 >>> x={} >>> x[42]='Foobar' >>> x {42: 'Foobar'}
字典示例:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#简单数据库 #使用人名作为键的字典。每个人用另一个字典来表示,其键‘phone’和‘addr’分别表示他们的电话号码和地址 people = { 'Alice' : { 'phone' : '2341', 'addr' : 'Foo drive 23' }, 'Beth' : { 'phone' : '9102', 'addr' : 'Bar street 42' }, 'Cecil' : { 'phone' : '3158', 'addr' : 'Baz avenue 90' } } #针对电话号码和地址使用的描述性标签,会再打印输出的时候用到 labels = { 'phone' : 'phone number', 'addr' : 'address' } name = input('Name: ') #查找电话号码还是地址?使用正确的键: request = input("Phone number(p) or address(a)?") if request == 'p' : key = 'phone' if request == 'a' : key = 'addr' #如果名字是字典中的有效键才打印信息: if name in people : print("%s's %s is %s." % \ (name, labels[key], people[name][key]))
3)字典的格式化字符串——在每个转换说明符(conversion specifier)中的%字符后面,加上(用圆括号括起来的)键,后跟其他说明元素
>>> phonebook={'Alice':'2341','Beth':'9102','Cecil':'3258'} >>> "Cecil's phone number is %(Cecil)s." % phonebook "Cecil's phone number is 3258."
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> template = '''<html> <head><title>%(title)s</title></head> <h1>%(title)s</h1> <p>%(text)s</p> </body>''' >>> data = {'title':'My Home Page','text':'Welcome to my home page!'} >>> print(template % data) <html> <head><title>My Home Page</title></head> <h1>My Home Page</h1> <p>Welcome to my home page!</p> </body>
4)字典方法
(1) clear 方法 ——清除字典中所有的项目。这是个原地操作(类似list.sort),无返回值(或者说返回None)
>>> x={} >>> y=x >>> x['key']='value' >>> y {'key': 'value'} >>> x.clear() # 如果使用: x = {},则y还是 {'key':'value'} >>> y {}
(2) copy 方法 —— 返回一个具有相同键值对的新字典(这个方法实现的是浅复制(shallow copy),因为值本身就是相同的,而不是副本)。
>>> x = {'username':'admin','machines':['foo','bar','baz']} >>> y = x.copy() >>> y['username'] = 'mlh' >>> y['machines'].remove('bar') >>> y {'username': 'mlh', 'machines': ['foo', 'baz']} >>> x {'username': 'admin', 'machines': ['foo', 'baz']}
可以看到,当在副本中替换值的时候,原始字典不受影响,但是如果修改了某个值(原地修改,而不是替换),原始的字典也会改变,因为同样的值也存储在原字典中。避免这个问题的一种方法就是使用深复制(deep copy),复制其包含所有的值。使用copy模块的deepcopy函数完成操作:
>>> from copy import deepcopy >>> d = {} >>> d['names'] = ['Alfred', 'Bertrand'] >>> c = d.copy() >>> dc = deepcopy(d) >>> d['names'].append('Clive') >>> c {'names': ['Alfred', 'Bertrand', 'Clive']} >>> dc {'names': ['Alfred', 'Bertrand']}
3)fromkeys 方法 —— 使用给定的键建立新的字典,每个键默认对应的值为None
>>> {}.fromkeys(['name','age']) {'age': None, 'name': None}
也可以直接在所有字典的类型 dict 上面调用方法
>>> dict.fromkeys(['name','age']) {'age': None, 'name': None} #如果不想使用None作为默认值,也可以自己提供默认值 >>> dict.fromkeys(['name','age'],'(unknown)') {'age': '(unknown)', 'name': '(unknown)'}
4)get 方法 —— 是更宽松的访问字典项的方法。一般如果试图访问字典中不存在的项时会出错,而get不会:
>>> d={} >>> print(d.get('name')) None
还可以自定义“默认”值,替换None
>>> d.get('name','N/A') 'N/A'
示例:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#简单数据库 #使用人名作为键的字典。每个人用另一个字典来表示,其键‘phone’和‘addr’分别表示他们的电话号码和地址 people = { 'Alice' : { 'phone' : '2341', 'addr' : 'Foo drive 23' }, 'Beth' : { 'phone' : '9102', 'addr' : 'Bar street 42' }, 'Cecil' : { 'phone' : '3158', 'addr' : 'Baz avenue 90' } } #针对电话号码和地址使用的描述性标签,会再打印输出的时候用到 labels = { 'phone' : 'phone number', 'addr' : 'address' } name = input('Name: ') #查找电话号码还是地址?使用正确的键: request = input("Phone number(p) or address(a)?") if request == 'p' : key = 'phone' if request == 'a' : key = 'addr' #使用get()提供默认值: person = people.get(name,{}) label = labels.get(key) result = person.get(key, 'not available') print("%s's %s is %s." % (name,label, result)) #如果名字是字典中的有效键才打印信息: #if name in people : print("%s's %s is %s." % \ # (name, labels[key], people[name][key]))
5)has_key 方法 —— 检查字典中是否含有给出的键。表达式 d.has_key(k) 相对于表达式 k in d。Python3.0不包含此函数
6)items 和 iteritems
items 方法 将所有的字典项以列表方式返回,返回时没有特殊的顺序
>>> d = {'title':'Python Web Site', 'url':'http://www/python.org', 'spam':0} >>> d.items() dict_items([('url', 'http://www/python.org'), ('title', 'Python Web Site'), ('spam', 0)])
iteritems 方法 作用大致相同,但是会返回一个迭代器对象而不是列表
7)keys 和 iterkeys —— keys 方法将字典中的键以列表形式返回,而iterkeys返回针对键的迭代器
8)pop 方法 —— 用来获取对应于给定键的值,然后将这个键-值从字典中移除
>>> d={'x':1,'y':2} >>> d.pop('x') 1 >>> d {'y': 2}
9)popitem 方法—— 类似list.pop,后者会弹出列表的最后一个元素。不同的是,popitem弹出随机的项,因为字典并没有“最后的元素”或者其他有关顺序的概念。若想一个接一个的移除并处理项,这个方法很有效(因为不用首先获取键的列表)
>>> d = {'title':'Python Web Site', 'url':'http://www/python.org', 'spam':0} >>> d.popitem() ('url', 'http://www/python.org') >>> d {'title': 'Python Web Site', 'spam': 0}
10)setdefault 方法 —— 在某种程度上类似get方法,就是能够获得与给定键相关联的值,除此之外,还能在字典中不含有给定键的情况下设定相应的键值:
>>> d={} >>> d.setdefault('name','N/A') 'N/A' >>> d {'name': 'N/A'} >>> d['name']='Gumby' >>> d.setdefault('name','N/A') 'Gumby' >>> d {'name': 'Gumby'}
可以看出,键不存在时,setdefault返回默认值并且相应的更新字典。如果键存在,那么就返回与其对应的值,但不改变字典。默认值是可选的,默认为None
11)update 方法 —— 可以利用一个字典项更新另外一个字典。提供的字典中的项会被添加到旧的字典中,若有相同的键则会进行覆盖:
>>> d={'title':'Python Web Site','url':'http://www.python.org','changed':'Mar 14 22:09:15 MET 2008'} >>> x={'title':'Python Language Web'} >>> d.update(x) >>> d {'url': 'http://www.python.org', 'title': 'Python Language Web', 'changed': 'Mar 14 22:09:15 MET 2008'}
12)values 和 itervalues 方法 —— values 方法以列表的形式返回字典中的值,与返回键的列表不同的是,返回值的列表中可以包含重复的元素:
>>> d={} >>> d[1]=1 >>> d[2]=2 >>> d[3]=3 >>> d[4]=4 >>> d.values() dict_values([1, 2, 3, 4]) >>> list(d.values()) [1, 2, 3, 4]
小结:
映射:映射可以使用任何不变对象标识元素。最常用的类型是字符串和元组。python唯一内建映射类型是字典
利用字典格式化字符串:可以通过在格式化说明符中包括名称(键)来对字典应用字符串格式化操作。
字典的方法