目录总览
一、if分支结构
分支结构就是根据条件判断的真假去执行不同分支对应的子代码
# if 语句
if 表达式:
代码块
# if else 语句
if 表达式:
代码块1
else:
代码块2
# if elif else 语句
if 表达式1:
代码块1
elif 表达式2:
代码块2
elif 表达式3:
代码块3
else:
代码块n
1.注意事项
-
if、elif、else 语句的最后都有冒号
:
-
elif 和 else 都不能单独使用必须和 if 一起出现,且要正确配对
-
表达式可以是单一的值或者变量,也可以是由运算符组成的复杂语句,但执行结果必须为布尔类型
-
一旦某个表达式成立就会执行它后面对应的代码块;如果所有表达式都不成立,就执行 else 后面的代码块;如果没有 else 部分,那就什么也不执行
-
在if判断中所有数据类型都会自动转换成布尔类型,用作布尔表达式(如用作if语句中的条件)时,下面的值都将被解释器视为假,但它们并不相等:
False None 0 “” () [] {}
-
换而言之,标准值False和None、各种类型(包括浮点数、复数等)的数值0、空序列(如空
字符串、空元组和空列表)以及空映射(如空字典)都被视为假,而其他各种值都被视为真,
包括特殊值True
2.缩进要求
- 不要忘记缩进
if、elif 和 else 后面的代码块一定要缩进,而且缩进量要大于 if、elif 和 else 本身
- 缩进1 个 Tab 键
Python 要求代码块必须缩进,缩进量不限,建议缩进 1 个 Tab 键的位置或缩进 4 个空格;两者等价
- 所有语句都要缩进,且同一代码块缩进量要相同
一个代码块的所有语句都要缩进,而且缩进量必须相同。
- 不要随便缩进
不需要使用代码块的地方千万不要缩进,一旦缩进就会产生一个代码块
3.语句嵌套
if、if else 和 if elif else,这 3 种条件语句间可相互嵌套
# 在最简单的 if 语句中嵌套 if else 语句
if 表达式1:
if 表示式2:
代码块1
else:
代码块2
# 在 if else 语句中嵌套 if else 语句
if 表示式 1:
if 表达式2:
代码块1
else:
代码块2
else:
if 表达式3:
代码块3
else:
代码块4
if、if else 和 if elif else 之间可相互嵌套。开发程序时根据场景需要选择合适的嵌套方案。在相互嵌套时,一定要严格遵守不同级别代码块的缩进规范
number = int(input('Enter a number between 1 and 10: '))
if number <= 10:
if number >= 1:
print('Great!')
else:
print('Wrong!')
else:
print('Wrong!')
# 这有点笨拙,因为输入了print('Wrong!')两次。
number = int(input('Enter a number between 1 and 10: '))
if number <= 10 and number >= 1:
print('Great!')
else:
print('Wrong!')
# 通过使用链式比较1 <= number <= 10可进一步简化示例。
number = int(input('Enter a number between 1 and 10: '))
if 1 <= number <= 10:
print('Great!')
else:
print('Wrong!')
4.三目运算符
# 语法:条件为真时的结果 if 判断的条件 else 条件为假时的结果
a if a>b else c if c>d else d
# 应该理解为
a if a>b else ( c if c>d else d )
二、循环结构
python中有while与for两种循环机制,其中while循环称之为条件循环
1.while
while 条件表达式:
代码块
# 此代码块指缩进格式相同的多行代码,在循环结构中,代码块又称为循环体
-
while 语句执行流程:
首先判断条件表达式的值,其值为真(True)时执行代码块中的语句,执行完毕后,再回来重新判断条件表达式的值是否为真,若仍为真,则继续重新执行代码块…如此循环,直到条件表达式的值为假(False)才终止循环
注意:使用 while 循环时要保证循环条件有变假时(循环结构中至少有一个位置能让循环条件为 False 或让 break 语句得以执行),否则将成为死循环(无法结束循环)。纯计算无IO的死循环会导致致命的效率问题
2.for
循环结构的第二种方式for循环可做的while循环都可实现,但在循环取值(即遍历值)时for循环比while循环更为简洁。它常用于遍历字符串、列表、元组、字典、集合等序列类型,逐个获取序列中的各个元素。只要能够使用for循环,就不要使用while循环。
# for 循环的语法格式
for 变量名 in 可迭代对象:
代码一
代码二
...
for item in ['a','b','c']:
print(item) # a b c
# 步骤1:从列表['a','b','c']中读出第一个值赋值给item(item=‘a’),然后执行循环体代码
# 步骤2:从列表['a','b','c']中读出第二个值赋值给item(item=‘b’),然后执行循环体代码
# 步骤3: 重复以上过程直到列表中的值读尽
列表推导式:
# 列表推导式语法:
[ 表达式 for 变量 in range(起始位置, 结束位置, 步长) ]
# 根据需求快速生成一个列表
a = [i for i in range(4)]
print(a) #输出结果:[0, 1, 2, 3]
a = [x for x in range(3, 4)] #结果:a = 3
# 在循环的过程中使用if
a = [x for x in range(3, 10) if x % 2 == 0] #结果:a = [4,6,8]
# 普通方式创建列表
a = []
for i in range(100):
a.append(i)
print(a)
# 推导式创建列表
a = [value for value in range(100)]
print(a)
# 创建⼀个包含10个随机数的列表
import random
my_list = [random.randint(1, 10) for _ in range(10)]
print(my_list)
# 将上⾯列表中的元素, 加 10
new_list = [value + 10 for value in my_list]
print(new_list)
# 序列中所有的偶数组合成列表
my_list = [value for value in range(10) if value % 2 == 0]
print(my_list)
# 输出:
# [1, 2, 9, 5, 10, 3, 9, 7, 2, 6]
# [11, 12, 19, 15, 20, 13, 19, 17, 12, 16]
# [0, 2, 4, 6, 8]
1)迭代字典
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
print(key, 'corresponds to', d[key])
# x corresponds to 1
# y corresponds to 2
# z corresponds to 3
# 也可使用keys等字典方法来获取所有的键。如果只对值感兴趣,可使用d.values。你可能还记得,d.items以元组的方式返回键值对。for循环的优点之一是,可在其中使用序列解包。
for key, value in d.items():
print(key, 'corresponds to', value)
# x corresponds to 1
# y corresponds to 2
# z corresponds to 3
# 字典元素的排列顺序是不确定的。换而言之,迭代字典的键或值时,一定会处理所有的键或值,但不知道处理的顺序。
2)并行迭代
# 同时迭代两个序列:
names = ['anne', 'beth', 'george', 'damon']
ages = [12, 45, 32, 102]
# 打印名字和对应的年龄,i是用作循环索引的变量的标准名称。
for i in range(len(names)):
print(names[i], 'is', ages[i], 'years old')
# anne is 12 years old
# beth is 45 years old
# george is 32 years old
# damon is 102 years old
zip()
并行迭代工具是内置函数zip,它将两个序列“缝合”起来,并返回一个由元组组成的序列。返回值是一个适合迭代的对象,要查看其内容,可使用list将其转换为列表。
print(list(zip(names, ages)))
# [('anne', 12), ('beth', 45), ('george', 32), ('damon', 102)]
# “缝合”后,可在循环中将元组解包。
for name, age in zip(names, ages):
print(name, 'is', age, 'years old')
# anne is 12 years old
# beth is 45 years old
# george is 32 years old
# damon is 102 years old
record_sum.sort(reverse=True)
# 函数zip可用于“缝合”任意数量的序列。需要指出的是,当序列的长度不同时,函数zip将在最短的序列用完后停止“缝合”。
print(list(zip(range(5), range(100000000))))
# [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
3)获取索引
在迭代对象序列的同时获取当前对象的索引
# 如替换一个字符串列表中所有包含子串'xxx'的字符串。假设:
for string in strings:
if 'xxx' in string:
index = strings.index(string) # 在字符串列表中查找字符串
strings[index] = '[censored]'
# 上面替换前的搜索没有必要。如果没有替换,搜索返回的索引(即返回的是该字符串首次出现处的索引)就为-1,下面的语句会报错。下面是一种更佳的解决方案:
index = 0
for string in strings:
if 'xxx' in string:
strings[index] = '[censored]'
index += 1
enumerate()
能够迭代索引-值对,其中的索引是自动提供的
# 无需设置index变量,直接获取索引和索引对应的值
for index, string in enumerate(strings):
if 'xxx' in string:
strings[index] = '[censored]'
4)反向迭代
reversed和sorted类似于列表方法reverse和sort(sorted接受的参数也与sort类似),但可用于任何序列或可迭代的对象,且不就地修改对象,而是返回反转和排序后的版本
# sorted返回一个列表,而reversed像zip返回可迭代对象,不能对可迭代对象执行索引或切片操作,也不能直接对可迭代对象调用列表的方法。要执行这些操作,可先使用list对返回的对象进行转换。
print(list(reversed('Hello, world!')))
# ['!', 'd', 'l', 'r', 'o', 'w', ' ', ',', 'o', 'l', 'l', 'e', 'H']
print(''.join(reversed('Hello, world!')))
# !dlrow ,olleH
5)排序迭代
要按字母表排序,可先转换为小写。为此,可将sort或sorted的key参数设置为str.lower。例如,sorted(“aBc”, key=str.lower)返回[‘a’, ‘B’, ‘c’]
print(sorted([4, 3, 6, 8, 3]))
# [3, 3, 4, 6, 8]
print(sorted('Hello, world!'))
# [' ', '!', ',', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w']
6)列表推导
列表推导是一种从其他列表创建列表的方式,类似于数学中的集合推导。列表推导的工作原理非常简单,有点类似于for循环。
print([x * x for x in range(10)])
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 这个列表由range(10)内每个值的平方组成。只打印能被3整除的平方值,可使用求模运算符:
# 如果y能被3整除,y 3 % 将返回0(请注意,仅当x能被3整除时,x*x才能被3整除)。
# 可在列表推导中添加一条if语句。
print([x * x for x in range(10) if x % 3 == 0])
# [0, 9, 36, 81]
# 还可添加更多的for部分。
print([(x, y) for x in range(3) for y in range(3)])
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
# 作为对比,下面的两个for循环创建同样地列表:
result = []
for x in range(3):
for y in range(3):
result.append((x, y))
print(result)
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
使用多个for部分时,也可添加if子句。
# 这些代码将名字的首字母相同的男孩和女孩配对。
girls = ['alice', 'bernice', 'clarice']
boys = ['chris', 'arnold', 'bob']
print([b + '+' + g for b in boys for g in girls if b[0] == g[0]])
# ['chris+clarice', 'arnold+alice', 'bob+bernice']
# 前述男孩/女孩配对示例的效率不太高,因为它要检查每种可能的配对。
girls = ['alice', 'bernice', 'clarice']
boys = ['chris', 'arnold', 'bob']
letterGirls = {} # 创建一个名为letterGirls的字典
for girl in girls: # 字典键为girls中每个名字首字母,值为该名字
letterGirls.setdefault(girl[0], []).append(girl)
print([b + '+' + g for b in boys for g in letterGirls[b[0]]]) # 用boys中名字首字母作为键在letterGirls字典中查找,找的则返回键对应的值
# ['chris+clarice', 'arnold+alice', 'bob+bernice']
使用圆括号代替方括号并不能实现元组推导,而是将创建生成器,可使用花括号来执行字典推导。
# 在列表推导中for前面只有一个表达式,而在字典推导中,for前面有两个用冒号分隔的表达式。这两个表达式分别为键及其对应的值
squares = {i: "{} squared is {}".format(i, i ** 2) for i in range(10)}
print(squares[8])
# 8 squared is 64
3.else
while 循环和 for 循环其后都可紧跟着一个 else 代码块,当循环正常执行完且中间没有被break 中止就会执行else后面的语句,所以可用else来验证循环是否正常结束。
如果执行过程中被break,就不会执行else的语句
count = 0
while count <= 5 :
count += 1
print("Loop",count)
else:
print("循环正常执行完啦")
print("-----out of while loop ------")
# 输出
# Loop 1
# Loop 2
# Loop 3
# Loop 4
# Loop 5
# Loop 6
# 循环正常执行完啦 #没有被break打断,所以执行了该行代码
# -----out of while loop ------
# 如果执行过程中被break,就不会执行else的语句
count = 0
while count <= 5 :
count += 1
if count == 3:
break
print("Loop",count)
else:
print("循环正常执行完啦")
print("-----out of while loop ------")
# 输出
# Loop 1
# Loop 2
# -----out of while loop ------ #由于循环被break打断了,所以不执行else后的输出语句
4.循环嵌套
while 和 for 循环结构也支持嵌套。当 2 个(甚至多个)循环结构相互嵌套时,位于外层的循环结构常简称为外层循环或外循环,位于内层的循环结构常简称为内层循环或内循环。
循环嵌套结构的代码,Python 解释器执行的流程为:
- 当外层循环条件为 True 时,则执行外层循环结构中的循环体;
- 外层循环体中包含了普通程序和内循环,当内循环的循环条件为 True 时会执行此循环中的循环体,直到内循环条件为 False,跳出内循环;
- 若外层循环的条件仍为 True,则返回第 2 步继续执行外层循环体,直到外层循环的循环条件为 False;
- 当内层循环的循环条件为 False,且外层循环的循环条件也为 False,则整个嵌套循环才算执行完毕
嵌套循环执行的总次数 = 外循环执行次数 * 内循环执行次数
- if 语句和循环(while、for)结构之间,也可以相互嵌套
i = 0
if i<10:
for j in range(5):
print("i=",i," j=",j)
- if、while、for 之间支持多层( ≥3 )嵌套
if ...:
while ...:
for ...:
if ...:
...
三、语句关键字
1.pass
在实际开发中,有时会先搭建起程序的整体逻辑结构,但暂时不去实现某些细节。程序有时需要占一个位置或放一条语句,但又不希望这条语句做任何事情,此时可以通过 pass 语句来实现。pass 是 Python 中的关键字,用来让解释器跳过此处,什么都不做。
if name == 'Ralph Auldus Melish':
print('Welcome!')
elif name == 'Enid':
# 还未完成……
elif name == 'Bill Gates':
print('Access Denied')
# 这些代码不能运行,因为在Python中代码块不能为空。要修复这个问题,只需在中间的代码块中添加一条pass语句即可。
if name == 'Ralph Auldus Melish':
print('Welcome!')
elif name == 'Enid':
# 还未完成……
pass
elif name == 'Bill Gates':
print('Access Denied')
也可不使用注释和pass语句,而是插入一个字符串。这种做法尤其适用于未完成的函数和类,因为这种字符串将充当文档字符串
2.assert
assert 语句又称断言语句,用于判断某个表达式的值,若值为真,则程序继续向下执行;反之主动报错,执行可用 if 语句表示。assert 在错误条件出现时直接让程序崩溃。常用于检查用户的输入是否符合规定,还常用作程序初期测试和调试过程中的辅助工具
if 表达式==True:
程序继续执行
else:
程序报 AssertionError 错误
assert 的检查可以关闭,在命令行模式下运行 Python 程序时,加入 -O 选项可以使程序中的 assert 失效。一旦 assert 失效,其包含的语句也就不会被执行
3.break
在执行 while 循环或者 for 循环时,Python提供了 2 种强制离开当前循环体的办法
- 使用 continue 语句,可以跳过执行本次循环体中剩余的代码,转而执行下一次的循环
- 只用 break 语句,可以完全终止当前循环
break用法
- break 语句可立即终止当前循环的执行,跳出当前所在的循环结构。无论是 while 循环还是 for 循环,只要执行 break 语句,就会直接结束当前正在执行的循环体。
- break 语句的语法只需要在相应 while 或 for 语句中直接加入即可
- break 语句一般结合 if 语句进行搭配使用,表示在某种条件下跳出循环体
username = "jason"
password = "123"
# 记录错误验证的次数
count = 0
while count < 3:
inp_name = input("请输入用户名:")
inp_pwd = input("请输入密码:")
if inp_name == username and inp_pwd == password:
print("登陆成功")
break # 用于结束本层循环
else:
print("输入的用户名或密码错误!")
count += 1
循环嵌套+break
如果循环嵌套了很多层,要想退出每一层循环则需要在每一层循环都有一个break
username = "jason"
password = "123"
count = 0
while count < 3: # 第一层循环
inp_name = input("请输入用户名:")
inp_pwd = input("请输入密码:")
if inp_name == username and inp_pwd == password:
print("登陆成功")
while True: # 第二层循环
cmd = input('>>: ')
if cmd == 'quit':
break # 用于结束本层循环,即第二层循环
print('run <%s>' % cmd)
break # 用于结束本层循环,即第一层循环
else:
print("输入的用户名或密码错误!")
count += 1
针对嵌套多层的while循环,若很明确要在某一层直接退出所有层的循环,其实就让所有while循环的条件都用同一变量,该变量的初始值为True,一旦在某一层将该变量的值改成False,则所有层的循环都结束
username = "jason"
password = "123"
count = 0
tag = True
while tag:
inp_name = input("请输入用户名:")
inp_pwd = input("请输入密码:")
if inp_name == username and inp_pwd == password:
print("登陆成功")
while tag:
cmd = input('>>: ')
if cmd == 'quit':
tag = False # tag变为False, 所有while循环的条件都变为False
break
print('run <%s>' % cmd)
break # 用于结束本层循环,即第一层循环
else:
print("输入的用户名或密码错误!")
count += 1
4.continue
和 break 语句相比,continue 语句只会终止执行本次循环中剩下的代码,直接从下一次循环继续执行。continue 语句的用法和 break 语句一样,只要 while 或 for 语句中的相应位置加入即可
# 打印1到10之间,除7以外的所有数字
number=11
while number>1:
number -= 1
if number==7:
continue
# 结束掉本次循环,即本次循环continue之后的代码都不会运行了,而是直接进入下一次循环
print(number)
四、迭代器(Iterator)
迭代器是迭代取值的工具,迭代器基于索引迭代取值的局限性,能够不依赖于索引的取值方式
迭代是一个重复的过程,每次重复都基于上一次的结果而继续。单纯的重复不是迭代。
可多个值循环列举的类型有:列表,字符串,元祖,字典,集合,文件
l = [1,2,3]
i = 0
while i<len(l):
print(l[i])
i+=1
#上述索引迭代取值的方式只适用于有索引的数据类型:列表,字符串,元祖
1.对象
- 可迭代对象(可以转换成迭代器的对象):内置有__iter__方法的对象都是可迭代对象,字符串、列表、元组、字典、集合、打开的文件都是可迭代对象。
- 可迭代对象.iter():得到迭代器对象
- 迭代器对象:迭代器对象(Iterator)是调用obj.iter()方法返回的结果,是内置有iter和next方法的对象,打开的文件是迭代器对象。
- 迭代器对象.next():得到迭代器的下一个值
- 迭代器对象.iter():得到迭代器的本身
d = {'a': 1, 'b': 2}
d_iter = iter(d)
count = 0
while count < len(d):
print(next(d_iter))
count += 1
print('%' * 20)
# a
# b
# %%%%%%%%%%%%%%%%%%%%
d = {'a':1,'b':2}
d_iter = iter(d)
print(d_iter is iter(d_iter))
# True
2.优缺点
优点
- 为序列和非序列类型提供了一种统一的迭代取值方式
- 惰性计算:节省内存。迭代器对象表示的是一个数据流,可以只在需要时去调用next来计算出一个值
- 就迭代器本身,同一时刻在内存中仅有一个值,因而可存放无限大的数据流
- 其他容器类型如列表,需把所有元素都存放于内存中,受内存大小的限制,可存放值的个数有限
缺点
- 除非取尽,否则无法获取迭代器的长度(只有在next完毕才知道到底有几个值)。
- 只能取下一个值,不能回到开始,一次性的只能往后走而不能往前退。
- 迭代器产生后唯一目标就是重复执行next方法直到值取尽,否则会停留在某位置等待下一次调用next
- 再次迭代同个对象,只能重新调用iter方法创建新迭代器对象,若有两个或者多个循环使用同一迭代器,只有一个循环能取到值
3.再谈for循环
for循环原理是迭代器使用while循环的简化
- 迭代器使用while循环的实现方式如下
goods=['mac','lenovo','acer','dell','sony']
i=iter(goods) #每次都需要重新获取一个迭代器对象
while True:
try:
print(next(i))
except StopIteration: #捕捉异常终止循环
break
# mac
# lenovo
# acer
# dell
# sony
- for循环又称为迭代循环,in后可以跟任意可迭代对象,上述while循环可以简写为
goods=['mac','lenovo','acer','dell','sony']
for item in goods:
print(item)
- for 循环首先会调用可迭代对象goods内置的iter方法拿到一个迭代器对象,然后再调用该迭代器对象的next方法将取到的值赋给item,执行循环体完成一次循环,周而复始,直到捕捉StopIteration异常,结束迭代
# for循环可以称之为迭代循环
d = {'a':1,'b':2}
for k in d:
print(k)
# 1. d.__iter__()得到一个迭代器对象
# 2. 迭代器对象.__next__()拿到一个返回值,然后将该返回值赋值给k
# 3. 循环往复步骤2,直到抛出异常,for循环户捕捉异常然后结束循环
- for循环的本质就是调用next()
4.常用函数
函数map、reduce、filter都支持迭代器协议,用来处理可迭代对象
# 设可迭代对象array为例来介绍它们三个的用法
array=[1,2,3,4,5]
1)map()
map函数平方可迭代对象的每个元素
# map函数可以接收两个参数,一个是函数,另外一个是可迭代对象,具体用法如下
array=[1,2,3,4,5]
res=map(lambda x:x**2,array)
print(res)
print(list(res))
# <map object at 0x00000262D0FD5D80>
# [1, 4, 9, 16, 25]
解析:map会依次迭代array,得到的值依次传给匿名函数(也可以是有名函数),而map函数得到的结果仍然是迭代器
2)reduce()
reduce函数合并可迭代对象
注意:reduce在python3中被集成到模块functools中,需要导入才能使用
# reduce函数可以接收三个参数,一个是函数,第二个是可迭代对象,第三个是初始值
from functools import reduce
array=[1,2,3,4,5]
res=reduce(lambda x,y:x+y,array)
print(res)
# 15
# 解析:没有初始值时reduce函数会先迭代一次array得到值1作为初始值传给第一个值x,然后继续迭代一次array得到值2传给第二个值y,运算的结果为3,将上一次reduce运算的结果作为第一个值传给x,然后迭代一次array得到的结果3作为第二个值传给y,依次类推,迭代完array的所有元素得到最终结果15
# 也可以为reduce指定初始值
from functools import reduce
array=[1,2,3,4,5]
res = reduce(lambda x,y:x+y,array,100)
print(res)
# 115
3)filter()
filter函数过滤可迭代对象
array=[1,2,3,4,5]
res = filter(lambda x: x > 3, array)
print(list(res))
# [4, 5]
# 解析:filter函数会依次迭代array,得到的值依次传给匿名函数,如果匿名函数的返回值为真,则过滤出该元素,而filter函数得到的结果仍然是迭代器
提示:实际开发中,可以用列表生成式或生成器表达式来实现三者的功能
五、生成器(generator)
生成器就是自定义的迭代器
__next__ 不建议使用
next() 使用这种
def func():
print('第一次')
yield 1
print('第二次')
yield 2
g = func()
print(g)
# <generator object func at 0x00000233F90F4580>
# g 就是生成器,就是自定义的迭代器,会触发函数体代码的运行,然后遇到yield停下来,将yield后的值当做本次调用的结果返回
res = next(g)
print(res)
# 第一次
# 1
函数体内若存在yield关键字,调用函数不会执行函数体代码,而是返回生成器对象,即自定义的迭代器
# 应用案例
def my_range(start, stop, step=1):
while start < stop:
yield start
start += step
a = my_range(1, 7, 2)
print(next(a))
print(next(a))
print(next(a))
print(next(a))
# 1
# 3
# 5
# Traceback (most recent call last):
# File "C:\Users\14978\PycharmProjects\pythonProject\练习.py", line 9, in <module>
# print(next(a))
# StopIteration
for x in my_range(1, 7, 2):
print(x)
# 1
# 3
# 5
yield关键字是自定义迭代器的实现方式。不同于return,yield可用于返回值,但函数一旦遇到return就结束,而yield可以保存函数的运行状态挂起函数,用来返回多次值
def dog(name):
print('狗准备吃东西')
while True:
x = yield # x 拿到的是yield接收的值,yield可以接收到外部send传过来的数据并赋值给x
print('狗哥%s吃了%s' % (name, x))
yield # 针对表达式形式的yield,生成器对象必须事先被初始化一次,让函数挂起在food=yield的位置,等待调用g.send()方法为函数体传值,g.send(None)等同于next(g)
g = dog('旺旺')
g.send(None) # 等同于next(g)
g.send('一根骨头')
# 狗准备吃东西
# 狗哥旺旺吃了一根骨头
- 普通函数顺序执行,遇到return语句或者最后一行函数语句就返回
- generator函数在每次调用next()的时候执行,遇到yield语句暂停并返回数据到函数外,再次被next()调用时从上次返回的yield语句处继续执行
六、表达式之快速操作
1.三元表达式
三元表达式是一种简化代码的解决方案,语法如下
res = 条件成立时返回的值 if 条件 else 条件不成立时返回的值
def max2(x,y):
if x > y:
return x
else:
return y
res = max2(1,2)
# 用三元表达式可以一行解决
x=1
y=2
res = x if x > y else y # 三元表达式
2.列表生成式
列表生成式是一种简化代码的解决方案,用来快速生成列表
[expression for item1 in iterable1 if condition1]
或者:
[expression for item1 in iterable1]
# expression为新变量对旧变量的手段,item1为新变量,iterable1为旧变量,condition1为对新变量要求
l = ['muyi_nb', 'yimu_nb', 'lao_nb']
1.将所有小写字母转为大写
new_l = [x.upper() for x in l]
print(new_l)
# ['MUYI_NB', 'YIMU_NB', 'LAO_NB']
2.取出所有的_nb
new_l = [x.split('_')[0] for x in l]
print(new_l)
new_l = [x.replace('_nb', '') for x in l if x=='yimu_nb']
print(new_l)
# ['muyi', 'yimu', 'lao']
# ['yimu']
3.字典生成式
items = [('name','muyi'),('age',18),('sex','man')]
res = {k:v for k,v in items if k!='sex'}
print(res)
# {'name': 'muyi', 'age': 18}
4.集合生成式
keys = ['name','age','sex']
set1 = {key for key in keys}
print(set1,type(set1))
# {'age', 'sex', 'name'} <class 'set'>
3.生成器表达式
创建生成器对象有两种方式:
- 调用带yield关键字的函数
- 生成器表达式,与列表生成式的语法格式相同,只需要将[]换成()
(expression for item in iterable if condition)
# expression为新变量对旧变量的手段,item1为新变量,iterable1为旧变量,condition1为对新变量要求
对比列表生成式返回的是一个列表,生成器表达式返回的是一个生成器对象
# 对比列表生成式,生成器表达式的优点是节省内存(一次只产生一个值在内存中)
a=[x*x for x in range(3)]
print(a)
# a=[0, 1, 4]
g=(x*x for x in range(3))
print(g)
# <generator object <genexpr> at 0x101be0ba0>
next(g)
# 0
next(g)
# 1
next(g)
# 4
next(g) #抛出异常StopIteration
# 如果我们要读取一个大文件的字节数,应该基于生成器表达式的方式完成
with open('db.txt','rb') as f:
nums=(len(line) for line in f)
total_size=sum(nums) # 依次执行next(nums),然后累加到一起得到结果