文章目录
- Chap10 Python语句简介
- 重访Python程序结构
- Python的语句
- 两个if的故事
- Python增加了什么
- Python删除了什么
- 括号是可选的
- 终止行就是终止语句
- 缩进的结束就是代码块的结束
- Chap11 赋值、表达式和打印
- 赋值语句
- 赋值语句的形式
- 序列赋值
- 高级序列赋值语句模式
- Python3.0中的扩展序列解包
- 实际应用
- 边界情况
- 应用于for循环
- 多目标赋值语句
- 多目标赋值以及共享引用
- 增强的赋值语句
- 增强赋值以及共享引用
- 变量命名规则
- 保留字
- 命名惯例
- 变量名没有类型,但对象有
- 表达式语句
- 原处修改的一个常见的错误
- 打印
- 打印流重定向
- Chap12 if测试和语法规则
- if语句
- 通用格式
- 真值测试
- if/else三元表达式
- 更特殊的一些用法
- Chap13 while和for循环
- while循环
- 一般格式
- break,continue,pass和循环else
- 一般循环格式
- for循环
- 一般格式
- 例子
- 简单的例子
- Python3.0在for循环中扩展的序列赋值
- 嵌套for循环
- 利用循环读取文件
- 编写循环的技巧
- range常用的场合
- 并行遍历:zip和map
- 使用zip构造字典
- 产生偏移和元素:enumerate
- Chap14 迭代器和解析,第一部分
- 迭代器:初探
- 迭代的实现机制
- 手动迭代:iter和next
- 其它内置类型迭代器
- 列表解析:初探
- 列表解析基础知识
- 在文件上使用列表解析
- 扩展的列表解析语法
- 集合解析和字典解析
- Python3.0中的新的可迭代对象
- 多个迭代器VS单个迭代器
- 本部分相关习题
- 第一题
- 第二题
- 第三题
Chap10 Python语句简介
重访Python程序结构
本章深入学习内容:
- 程序由模块构成
- 模块包含语句
- 语句包含表达式
- 表达式建立并处理对象
Python的语句
语句 | 角色 | 例子 |
---|---|---|
赋值 | 创建引用之 | a,b,c=‘good’,‘bad’,‘ugly’ |
调用 | 执行函数 | log.write(“spam,ham”) |
打印调用 | 打印对象 | print(“The Killer”,joke) |
if/elif/else | 选择动作 | if “python” in text: print(text) |
for/else | 序列迭代 | for x in mylist: print(x) |
while/else | 一般循环 | while x>y: print(‘hello’) |
pass | 空占位符 | while True: pass |
break | 循环退出 | while True: if exittest(): break |
continue | 循环继续 | while True: if skiptest(): continue |
def | 函数和方法 | def f(a,b,c=1,*d): print(a+b+c+d[0]) |
return | 函数结果 | def f(a,b,c=1,*d): return a+b+c+d[0] |
yield | 生成器函数 | def gen(n): for i in n: >yield i*2 |
global | 命名空间 | x='old’ def function(): global x,y;x=‘new’ |
nonlocal | 命名空间(Python3.0及以上版本) | def outer(): x=‘old’ def function(): nonlocal x;x=‘new’ |
import | 模块访问 | import sys |
from | 属性访问 | from sys import stdin |
class | 创建对象 | class Subclass(Superclass): staticData=[] def method(self):pass |
try/except/finally | 捕捉异常 | try: action() except: print(‘action error’) |
raise | 触发异常 | raise EndSearch(location) |
assert | 调试检查 | assert X>Y,‘X too small’ |
with/as | 环境管理器(2.6) | with open(‘data’)as myfile: process(myfile) |
del | 删除引用 | del data[k] del data[i:j] del obj.attr del variable |
对以上内容的一些说明:
- 赋值语句以不同的语法形式呈现,有如针对基本的、序列的、扩展的等待
- 从技术上来讲,print在Python3.0中不是一个保留字,也不是一条语句,而是一个内置函数的调用
- yield实际上是一个表达式而不是一条语句
两个if的故事
Python中的if语句比其他语言的更简洁,条件判读不加圆括号,语句块不加花括号。
Python增加了什么
Python中新的语法成分是冒号(?。所有Python的复合语句(也就是语句中嵌套了语句)都有相同的一般形式,也就是首行以冒号结尾,首行下一行嵌套的代码往往按缩进的格式书写。
冒号是不可或缺的,遗漏掉冒号可能是Python新孚最常犯的错误之一 。
Python删除了什么
虽然Python需要额外的冒号,但是你必须在类C语言程序中加入,而通常不需要在 Python中加入的语法成分却有三项。
括号是可选的
Python中省略括号而语句依然会正常执行。
终止行就是终止语句
不会出现在Python程序代码中的第二个重要的语也成分就是分号。 Pytbon之中你不需要 像类C语言那样用分号终止语句。
缩进的结束就是代码块的结束
Chap11 赋值、表达式和打印
赋值语句
赋值语句很简单,但有些特性需要专门记住:
- 赋值语句建立对象引用值。Python赋值语句会把对象引用值存储在变量名或数据结构的元素内。赋值语句总是建立对象的引用值,而不是复制对象。
- 变量名在首次赋值时会被创建。
- 变量名在引用前必须先赋值。使用尚未进行赋值的变量名时一种错误。
- 执行隐式赋值的一些操作。模块导入、函数和类的定义、for循环变量以及函数参数全都是隐式赋值运算。
赋值语句的形式
运算 | 解释 |
---|---|
spam=‘Spam’ | 基本形式 |
spam,ham=‘yum’,‘YUM’ | 元组赋值运算(位置性) |
[spam,ham]=[‘yum’,‘YUM’] | 列表赋值运算(位置性) |
a,b,c,d=‘spam’ | 序列赋值运算,通用性 |
a,*b=‘spam’ | 扩展的序列解包(Python3.0) |
spam=ham=‘lunch’ | 多目标赋值运算 |
spams+=42 | 增强赋值运算 |
序列赋值
高级序列赋值语句模式
# 使用分片赋值
string='SPAM'
a,b,c=string[0],string[1],string[3]
a,b,c
('S', 'P', 'M')
a,b,c=list(string[:2])+[string[2:]]
a,b,c
('S', 'P', 'AM')
((a,b),c)=('SP','AM')
a,b,c
('S', 'P', 'AM')
#序列解包赋值
red,green,blue=range(3)
red,blue
(0, 2)
# 循环把序列分割为开头和剩余的两部分
L=[1,2,3,4]
while L:front,L=L[0],L[1:]print(front,L)
1 [2, 3, 4]
2 [3, 4]
3 [4]
4 []
# 上例的另一种实现
L=[1,2,3,4]
while L:front,L=L.pop(0),Lprint(front,L)
1 [2, 3, 4]
2 [3, 4]
3 [4]
4 []
Python3.0中的扩展序列解包
实际应用
在Python3.0中,可以在目标中使用*来更通用地匹配,这种方法等价于分片赋值,但更方便和简单:
seq=[1,2,3]
a,*b=seq
a,b
(1, [2, 3])
*a,b=seq
a,b
([1, 2], 3)
seq='spam'
a,*b,c=seq
a,b,c
('s', ['p', 'a'], 'm')
边界情况
一些值得注意的点:
- 带星号的名称可能只匹配单个的项,但仍会向其赋值一个列表
- 如果没有剩下的内容可以匹配带星号的名称,则会被赋值为一个空的列表,不管它出现在哪个位置
- 如果由多个带星号的名称,或者如果值少了而没有带星号的名称,以及如果带星号的名称自身没有编写到一个列表中,都会引发错误
seq=[1,2,3,4]
a,b,c,*d=seq
a,b,c,d
(1, 2, 3, [4])
a,b,c,d,*e=seq
a,b,c,d,e
(1, 2, 3, 4, [])
a,b,*c,d,e=seq
a,b,c,d,e
(1, 2, [], 3, 4)
a,*b,c,*d=seq
a,b,c,d
File "<ipython-input-16-13bccea04c44>", line 1a,*b,c,*d=seq^
SyntaxError: two starred expressions in assignment
a,b=seq
a,b
---------------------------------------------------------------------------ValueError Traceback (most recent call last)<ipython-input-17-0fc500ff2a50> in <module>()
----> 1 a,b=seq2 a,bValueError: too many values to unpack (expected 2)
*a=seq
a
File "<ipython-input-18-561b7861cc41>", line 1*a=seq^
SyntaxError: starred assignment target must be in a list or tuple
*a,=seq
a
[1, 2, 3, 4]
应用于for循环
for(a,*b,c)in [(1,2,3,4),(5,6,7,8)]:print(a,b,c)
1 [2, 3] 4
5 [6, 7] 8
多目标赋值语句
多目标赋值语句就是直接把所有提供的变量名都赋值给右侧的对象。
多目标赋值以及共享引用
对于不可在原处修改的对象:更改其中一个变量名不会影响其他变量;
对于可以在原处修改的对象:在原处更改其中一个变量名会影响其他变量。
a=b=c=1
print(a,b,c)
b=b+1
print(a,b,c)
1 1 1
1 2 1
a=b=c=[]
print(a,b,c)
b.append(23)
print(a,b,c)
[] [] []
[23] [23] [23]
a=b=c=[1,2,3]
print(a,b,c)
b.pop()
print(a,b,c)
[1, 2, 3] [1, 2, 3] [1, 2, 3]
[1, 2] [1, 2] [1, 2]
# 可在原处更改的对象,重新对其中一个变量赋值,不会影响其他对象
a=b=c=[1,2,3]
print(a,b,c)
b='string'
print(a,b,c)
[1, 2, 3] [1, 2, 3] [1, 2, 3]
[1, 2, 3] string [1, 2, 3]
增强的赋值语句
诸如+=、*=之类的赋值语句为增强的赋值语句
增强赋值以及共享引用
“+=”对列表和字典这类可变对象其实是在原处修改,并不像“+”合并,总是生成新的对象。当然对于不可变对象则不存在这种问题
L=[1,2]
M=L
L=L+[3,4]
L,M
([1, 2, 3, 4], [1, 2])
L=[1,2]
M=L
L+=[3,4]
L,M
([1, 2, 3, 4], [1, 2, 3, 4])
变量命名规则
Python变量命名需要遵循以下规则:
语法:(下划线或字母)+(任意数目的字母、数字或下划线)
区分大小写:SPAM和spam并不同
禁止使用保留字
保留字
Python3.0中的保留字:
False class finally is return
None continue for lambda try
True def from nonlocal while
and del global not with
as elif if or yield
assert else import pass
break except in raise
命名惯例
- 以单一下划线开头的变量名(_X)不会被from module import *语句导入
- 前后有下划线的变量名(__X__)是系统定义的变量名,对解释器有特殊意义
- 以两个下划线开头、但结尾没有两个下划线的变量名(__X)类的本地(“压缩”)变量
- 通过交互模式运行时,只有单个下划线的变量名(_)会保存最后表达式的结果
- 类的变量名通常以大写字母开头,而模块的变量名通常以小写字母开头
变量名没有类型,但对象有
变量有类型,并且可能是可变的或不可变的。变量名知识对象的引用值。没有不可变的观念,也没有相关联的类型信息,除了它们在特定时刻碰巧所引用的对象的类型。
表达式语句
原处修改的一个常见的错误
表达式语句通常用于执行可于远处修改列表的列表方法,然而初学者常常把这种运算写成赋值语句:
L=[1,2]
L.append(3)
L
[1, 2, 3]
L=L.append(4)
print(L)
None
对于像列表调用append、sort或reverse这类在原处的修改的运算,一定是对列表做原处的修改,但这些方法在列表修改后并不会把列表返回。事实上,它们返回的是None对象(可以理解成无返回值)。因此如果赋值这类运算的结果给该变量的变量名,只会丢失列表(gc)。
打印
打印流重定向
print(x,y)等价于:
import sys
sys.stdout.write(str(x)+’ ‘+str(y)+’\n’)
重定向使用格式一:
import sys
sys.stdout=open(‘log.txt’,‘a’) # redirects prints to a file
…
print(x,y) # shows up in log.txt
重定向使用格式二:(更一般的形式)
print(x,y,file=open(‘log.txt’,‘a’))
Chap12 if测试和语法规则
if语句
通用格式
if test1:
statements1
elif test2:
statements2
else:
statements3
真值测试
Python中:
- 任何非零数字或者非空对象都为真
- 数字零、空对象以及特殊对象None都被认作是假
- 比较和相等测试会递归地应用在数据结构中
- 比较和相等测试会返回True和False
- 布尔and和or运算符会返回真或假的操作对象
Python中三种布尔表达式运算符:
X and Y → 如果X和Y都是真,则为真,X为假不判断Y;
X or Y → 如果X或Y为真,则为真,X为真不判断Y;
not X → 如果X为假,则表达式为真
2<3,3<2
(True, False)
2 or 3,3 or 2,[] or 2,{} or []
(2, 3, 2, [])
2 and 3,3 and 2,{} and []
(3, 2, {})
if/else三元表达式
格式为
if x:
a=y
else:
a=z
等价于
a=y if x else z
更早的版本中则使用
a=((x and y) or z)
替代三元表达式
在Python中也可以使用如下表达式从列表中挑选真假值:
a=[z,y][bool(x)] (实际就是用布尔值构建下标)
['f','t'][bool('')]
'f'
['f','t'][bool('spam')]
't'
更特殊的一些用法
# 返回一组对象中第一个非空的那个,否则返回None
# 格式为 X=A or B or C or ... or None
X='' or [] or 'spam' or {'a':1} or None
print(X)# 常用在为某个变量指定一个默认值(如果未被赋值的话)
# X=A or default
A=''
B='spam'
def mydefault(x):my=x or 'my'print(my)
mydefault(A)
mydefault(B)
spam
my
spam
# 布尔运算符表达式若用来调用函数执行实质或重要的工作时,如果短路规则生效,则附加效果不会生效
# if f1() or f2():...
# 为了确保多个函数都会执行,应该在使用布尔表达式前先调用一遍
# tmp1,tmp2=f1(),f2()
# if tmp1 or tmp2:...
Chap13 while和for循环
while循环
一般格式
while test:
statements1
else:
statements2
break,continue,pass和循环else
在python中:
break→跳出最近所辖的循环(跳过整个循环语句)
continue→跳到最近虽遭循环的开头处(来到循环的首行)
pass→什么是也不做,只是空占位语句
循环else块→只有当循环正常离开时才执行(也就是没有碰到break语句)
一般循环格式
加入break和continue语句后,while循环的一般格式如下:
while test1:
statements1
if test2:break
if test3:continue
else:
statements2
for循环
for循环在Python中是一个通用的序列迭代器:可以遍历任何有序的序列对象内的元素。for语句可以用于字符串、列表、元组、其他内置可迭代对象以及之后能够通过类所创建的新的对象。
一般格式
for target in object:
statements1
else:
statements2
例子
简单的例子
# 一个元组迭代的简单例子
T=((1,2),(3,4),(5,6))
for a,b in T:print(a,b)
1 2
3 4
5 6
# 一个字典迭代的简单例子
D={'a':1,'b':2,'c':3}
for (key,value) in D.items() :print(key,'=>',value)
a => 1
b => 2
c => 3
Python3.0在for循环中扩展的序列赋值
在Python3.0中,由于一个序列可以赋值给一组更为通用的名称(其中有一个带有星号的名称收集多个元素),我们可以在for循环中使用同样的方法来提取嵌套的序列的部分:
L=[(1,2,3,4),(5,6,7,8)]
for (a,*b,c) in L:print(a,b,c)
1 [2, 3] 4
5 [6, 7] 8
嵌套for循环
items=['aaa',111,(4,5),2.01]
tests=[(4,5),3.14]
for key in tests:for item in items:if item == key:print(key,"was found!")breakelse:print(key,'not found!')
(4, 5) was found!
3.14 not found!
# in 能够隐式地进行循环扫描列表寻找匹配项,因此在if中使用in来判断而取代内嵌循环,效率会更高,程序也更简洁
for key in tests:if key in items:print(key,"was found!")else:print(key,"not found!")
(4, 5) was found!
3.14 not found!
利用循环读取文件
# 首先构建一个文件并添加内容
file=open('test.txt','w+')
L=['Hello World!\n','It is so nice to meet you!\n','I need to go.\n','See you later!']
file.writelines(L)
file.close()
#while 循环逐行读取
file=open('test.txt','r')
while True:line=file.readline()if not line:breakprint(line,end='')
file.close()
Hello World!
It is so nice to meet you!
I need to go.
See you later!
# for 循环逐行读取
file=open('test.txt','r')
for line in file.readlines():print(line,end='')
file.close()
Hello World!
It is so nice to meet you!
I need to go.
See you later!
编写循环的技巧
for循环博爱阔多数计数器式的循环。一般而言,for比while容易写,执行时也比较快。
但是,有些情况下,需要以更为特定的方式来进行迭代。python提供了两个内置函数,以在for循环内定制迭代:
- 内置range函数返回一系列连续增加的整数,可作为for中的所有;
- 内置zip函数返回并行元素的元组的列表,可用于在for中遍历数个序列。
L=[(1,2,3),'spam',3.14]
for x in range(len(L)):print('L[',x,'] is',L[x])
L[ 0 ] is (1, 2, 3)
L[ 1 ] is spam
L[ 2 ] is 3.14
注意点:除非有特殊需求,否则最好尽可能使用简单的for循环,不要使用while,并且不要在for中使用range调用,而是只将其视为最后的手段。
使用range的唯一真正有点是——它不会复制字符串,并且不会在Python3.0中创建一个列表,这对于很大的字符串来说,会很节省内存。
range常用的场合
# 指定步进切分字符串
string='abcdefghijklmn'
for x in range(0,len(string),2):print(string[x:x+2],end=',')
ab,cd,ef,gh,ij,kl,mn,
# 修改列表
L=[1,2,3,4,5]
for i in range(len(L)):L[i]+=1
L
[2, 3, 4, 5, 6]
# 实际上可以用列表解析来替代上例,且更高效
L=[1,2,3,4,5]
L=[x+1 for x in L]
L
[2, 3, 4, 5, 6]
并行遍历:zip和map
range允许我们以非完备的方式在for循环捏完成遍历。本着同样的精神,内置的zip函数也可以让我们使用for循环来并行使用多个序列。
# 假设有多个列表
L1=[1,2,3]
L2=[4,5,6]
L3=[7,8,9]
# 使用自拍创建一个元组以合并这些列表元素
Lall=list(zip(L1,L2,L3))
print(Lall)
# 使用for循环并行迭代
for(x,y,z) in zip(L1,L2,L3):print(x,y,z,'--',x+y+z)
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
1 4 7 -- 12
2 5 8 -- 15
3 6 9 -- 18
# 扩展,使用并行迭代输出多个列表
l1=[]
l2=[]
l3=[]
for (*x,) in zip(L1,L2,L3):l1.append(x.pop(0))l2.append(x.pop(0))l3.append(x.pop(0))
print(l1,l2,l3)
# 思考如何扩展以接受无上限的列表并输出
[1, 2, 3] [4, 5, 6] [7, 8, 9]
zip的一些注意点:
- zip可以接受任何类型的序列(即任何可迭代的对象,包括文件),并且可以有两个以上的参数
- 当参数长度不同是,zip会以最短序列的长度为准来截断所得到的元组
使用zip构造字典
keys=['spam','eggs','toast']
values=[1,3,5]
D={}
for (k,v) in zip(keys,values):D[k]=v
D
{'spam': 1, 'eggs': 3, 'toast': 5}
产生偏移和元素:enumerate
可以通过enumerate来产生偏移和元素,以替代range方法:
S='spam'
for(offset,item) in enumerate(S):print(item,'appears at offset',offset)
s appears at offset 0
p appears at offset 1
a appears at offset 2
m appears at offset 3
Chap14 迭代器和解析,第一部分
迭代器:初探
for循环可以用于Python中任何列类型,包括列表、元组以及字符串。但实际上,for循环甚至比这更为通用:可用于任何可迭代的对象。其实对Python中所有会从左到右扫描对象的迭代工具而言都是如此,这些迭代工具包括了for循环、列表解析、in成员关系测试等。
迭代的实现机制
Python中的迭代协议:有__next__方法的对象会前进到下一个结果,而在一系列结果的末尾时,则会引发StopIteration异常。在Python中,任何这类对象都是可迭代的。任何这类对象也能以for循环或其他迭代工具遍历,因此所有迭代工具内部工作来都是在每次迭代中调用__next__,并且捕捉StopIteration异常来确定何时离开。
手动迭代:iter和next
Python3.0提供了一个内置函数next,它会自动调用一个对象的__next__方法。给定一个可迭代对象,调用次方法等同于调用了__next__方法。
从技术的角度来讲,迭代协议还有一点值得注意。当for循环开始时,会通过它传给iter内置函数,以便从可迭代对象中获得一个迭代器,返回的对象含有需要的next方法。
但是对文件来说,可以直接使用next方法而不要通过内置的iter函数来产生一个迭代器,因为文件对象就是自己的迭代器。但是列表以及很多其他的内置对象,并不是自己的迭代器,因为它们支持对此打开迭代器。对这样的对象,必须调用iter来启动迭代。
其它内置类型迭代器
字典的迭代器有:keys方法,values方法,items方法,以及其自身(返回的其实是keys)
迭代协议也是我们必须要把某些结果包装到一个list调用中以一次性卡机难道它们的值的原因。因为可迭代的对象一次返回一个结果,而不是实际的列表。
列表解析:初探
列表解析基础知识
- 列表解析写在一个方括号里,因为它们最终是构建一个新的列表的方式。
- 解析表达式以一个循环变量开始,后边跟着应该看作是一个for循环的头部部分,它声明了循环变量以及一个可迭代对象
- 从技术上讲,列表解析并非真的是必须的,因为总是可以用一个for循环手动地构建一个表达式结果的列表
- 列表解析编写起来更加精简,且可以普遍使用于多种环境,此外列表解析比for循环运行更快(往往速度会快一倍),对于较大的数据集来说,使用列表解析更优
在文件上使用列表解析
f=open('test.txt')
lines=[line.rstrip() for line in f]
lines
['Hello World!','It is so nice to meet you!','I need to go.','See you later!']
# 由于列表解析项for循环语句一样是一个迭代环境,甚至可以不必提前打开文件,而是在表达式中打开,此时列表解析将自动使用迭代协议
lines=[line.rstrip() for line in open('test.txt')]
lines
['Hello World!','It is so nice to meet you!','I need to go.','See you later!']
扩展的列表解析语法
作为一个特别的扩展,表达式中嵌套的for循环可以有一个相关的if子句,来过滤那些测试部位真的结果项。
lines=[line.rstrip() for line in open('test.txt') if line[0]=='I']
lines
['It is so nice to meet you!', 'I need to go.']
如果需要的话,列表解析可以变得更复杂:例如它可能包含嵌套的循环,也可能被编写为一系列的for子句。实际上,列表解析的完整语法允许任意数目的for子句,每个子句有一个可选的相关的if子句(在20章会更加系统地介绍其语法)
[x+y for x in 'abc' for y in 'lmn']
['al', 'am', 'an', 'bl', 'bm', 'bn', 'cl', 'cm', 'cn']
# 快速输出乘法表
# 注意和上例的循环嵌套顺序的区别
print('\n'.join([' '.join(['%d*%d=%d'%(x,y,x*y) for x in range(1,y+1)])for y in range(1,10)]))
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
import time
L=[('吴俊杰','68'),('胡霞','98'),('陈立锦','64'),('陈琳','68'),('陈勇浩','73'),('陈仲珍','95'),('方怡彬','74'),('郭琦峰','76'),('郭如梦','82'),('黄航灵','98'),('黄诗铃','97'),('黄淑婵','71'),('黄雯婧','97'),('黄雨婷','61'),('黄长涛','98'),('江海明','68'),('李泓臻','65'),('李静','69'),('林晓萍','65'),('刘凤媚','81'),('罗曦','74'),('宁婉同','69'),('潘其威','60'),('戚鉴波','91'),('乔禹然','64'),('沙立','75'),('苏汝正','92'),('唐丹丹','83'),('滕芷娴','94'),('王彩','98'),('巫晓悦','91'),('吴瑜玲','93'),('闫梦瑶','79'),('杨雅婷','79'),('叶舟波','76'),('张彪','100'),('张丽亚','93'),('张琴心','67'),('张雨欣','86'),('庄子崧','70'),('邹咏琪','99'),('蔡巧真','77'),('陈文颖','96'),('陈羲','91'),('董晋业','63'),('高钰博','88'),('郭子玮','88'),('何叶灵','100'),('黄丹泓','71'),('江钰哲','62'),('姜子建','88'),('赖佳燕','91'),('李杰','81'),('李语萱','91'),('林瑞涵','74'),('林婷','82'),('林夏欣','95'),('林颖茹','79'),('刘玮','86'),('刘雨倩','89'),('刘至礼','75'),('卢蓓婕','82'),('孙帅','63'),('文正霞','80'),('吴伊凡','72'),('肖跃鹏','64'),('徐福顿','62'),('徐文鑫','83'),('徐晓璇','95'),('许慧卿','63'),('许焱鑫','73'),('姚瑶','85'),('俞珺','85'),('余悦','97'),('张灵涵','92'),('郑可立','61'),('钟灵','63'),('庄毓鸿','88'),('卓文浩','75'),('陈鸿宇','60'),('陈泓钊','78'),('陈景朝','97'),('陈俐琳','95'),('陈仁胜','61'),('陈少安','77'),('董锴','72'),('付雅媛','73'),('黄琳','65'),('黄伪龙','97'),('赖心如','79'),('兰子薇','73'),('李金星','93'),('李世平','73'),('梁伟杰','86'),('林雯琦','61'),('林宣宇','75'),('林志航','85'),('毛鑫平','94'),('彭阳','81'),('肖佳慧','79'),('谢国辉','91'),('杨彪','73'),('张家宸','83'),('张俊毅','92'),('张龙辉','67'),('张铭根','81'),('张宇斌','98'),('卓振烽','84'),('邹仕星','92'),('苏桂平','70')]t1=time.time()
scores=[eval(s) for n,s in L]
tot_score=0
for x in scores:tot_score+=x
ave_score=tot_score/len(L)
#print("平均分:%.2f"%(ave_score)))
t2=time.time()
print(t2-t1)
0.0009961128234863281
from functools import reduce
t3=time.time()
scores=[eval(L[row][1]) for row in range(len(L))]
tot_score_score=reduce((lambda x,y:x+y),scores)
ave_score=tot_score/len(L)
#print('平均分:%.2f'%(ave_score))
t4=time.time()
print(t4-t3)
0.0009968280792236328
如今的Python中,迭代西医甚至比目前所能展示的示例更为普遍——Python的内置工具集中从左到右地扫描一个对象的每项工具,都定义为在主体对象上使用了迭代协议。者甚至包含了更高级的工具,例如list和tuple内置函数(它们从可迭代杜希昂构建了一个新的对象),字符串join(将一个子字符串放置到一个可迭代对象中包含的字符串之间),甚至包括序列复制。总之,所有这些都将在一个打开的文件上工作并自动一次读取一行:
list(open('test.txt'))
['Hello World!\n','It is so nice to meet you!\n','I need to go.\n','See you later!']
tuple(open('test.txt'))
('Hello World!\n','It is so nice to meet you!\n','I need to go.\n','See you later!')
'&&'.join((open('test.txt')))
'Hello World!\n&&It is so nice to meet you!\n&&I need to go.\n&&See you later!'
集合解析和字典解析
和列表解析一样,集合解析和字典解析都支持列表解析的扩展语法,包括if测试。
Python3.0中的新的可迭代对象
Python3.0中的一个基本的改变是,它比Python2.X更强调迭代。除了于文件和字典这样的内置类型相关的迭代,字典方法keys、values、和items都在Python3.0中返回可迭代对象,就像内置函数range、map、zip和filter所作的那样。所有这些工具在Python3.0中都根据请求产生结果,而不像在Python2.6中那样构建结果列表。
把各种函数和方法调用的结果都包含到一个list调用中,从而迫使它们一次产生其所有的结果,因为Python3.0下上述工具不会直接返回列表而是返回一个可迭代对象。
多个迭代器VS单个迭代器
range内置函数支持len和索引,但它不是自己的迭代器,并且,它支持在其结果上的多个迭代器,这些迭代器会记住它们各自的位置:
R=range(3)
next(R)
---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-61-6acaa0ab8939> in <module>()1 R=range(3)
----> 2 next(R)TypeError: 'range' object is not an iterator
I1=iter(R)
print(next(I1))
print(next(I1))
0
1
I2=iter(R)
print(next(I2))
0
相反,zip、map和filter不支持相同结果上的多个活跃迭代器:
Z=zip((1,2,3),(4,5,6))
I1=iter(Z)
I2=iter(Z)
print(next(I1))
print(next(I2))
print(next(I1))
(1, 4)
(2, 5)
(3, 6)
M=map(abs,(-1,0,1))
I1=iter(M)
I2=iter(M)
print(next(I1),next(I2),next(I1))
1 0 1
本部分相关习题
第一题
编写基本循环
a.写个for循环,打印字符串S中每个字符的ASCII码。使用内置函数ord(char)把每个字符转换成ASCII整数
b.接着,修改循环来计算字符串中所有字符的ASCII码的总和
c.最后,再次修改代码,来返回一个新的列表,其中包含字符串中每个字符的ASCII码。表达式map(ord,S)是否有类似的效果?
S='this is my python'
for c in S:print(ord(c),end=' ')
116 104 105 115 32 105 115 32 109 121 32 112 121 116 104 111 110
flag=0
for c in S:flag+=ord(c)
print(flag)
1660
L1=[ord(c) for c in S]
print(L1)L2=list(map(ord,S))
print(L2)
[116, 104, 105, 115, 32, 105, 115, 32, 109, 121, 32, 112, 121, 116, 104, 111, 110]
[116, 104, 105, 115, 32, 105, 115, 32, 109, 121, 32, 112, 121, 116, 104, 111, 110]
第二题
排序字典。我们知道,字典是无序的集合体。编写一个for循环来按照排序后(递增)顺序打印字典的项目。提示:使用字典keys和列表sort方法,或者较新的sorted内置函数。
D={'milk':10,'apple':20,'banana':15,'egg':40}
K=sorted(list(D.keys()))
for k in K:print(k,'=>',D[k])
apple => 20
banana => 15
egg => 40
milk => 10
# list.sort()返回None,因此不能使用上述方法,即不能直接赋值
K=list(D.keys())
K.sort()
for k in K:print(k,'=>',D[k])
apple => 20
banana => 15
egg => 40
milk => 10
第三题
程序逻辑替代方案。考虑下列代码,是哦那个while循环以及found标志位来搜索2的幂值列表[到2的5次方].它保存在名为power.py的模块文件中。
L=[1,2,8,16,32,64]
X=5
found=False
i=0
while not found and i < len(L):if 2** X==L[i]:found=Trueelse:i=i+1if found:print('at index',i)else:print(X,'not found')
C:\book\tests>python power.py
at index 5
这个例子并没有遵循一般的Python代码编写的技巧。遵循这里所提到的步骤来改进它:
a. 首先,以while循环else分句重写这个代码来消除found标志位和最终的if语句
b. 接着,使用for循环和else分句重写这个例子,去掉列表索引运算逻辑。提示:要取得元素的索引,可以使用列表index方法(该方法返回列表中第一个元素的偏移量)
c. 接着,重写这个例子,改用简单的in运算符成员关系表达式,从而完全移除循环
d. 最后,使用for循环和列表append方法来产生列表,而不是通过列表常量硬编码
深入思考:
e. 把2**x表达式移到循环外,这样能够改善性能吗?如何编写代码?
f. 就像我们在练习1中看到过的,Python有一个map(function,list)工具也可以产生2次方的列表:map(lambda x:2 **x,range(7))。试着在交互模式下输入这段代码。
# 因为in隐式地运用了循环,因此上例完全可以不用while或者for循环语句
L=[2**x for x in range(7) ]
X=5
if 2**X in L:print('at index',L.index(2**X))
else:print(X,'not found')
at index 5
list(map(lambda x:2**x,range(7)))
[1, 2, 4, 8, 16, 32, 64]
# 用题目中d步骤来编写L列表
L=[]
for i in range(7):L.append(2**i)
L
[1, 2, 4, 8, 16, 32, 64]