一、推导式
推导式的引入提供了更加高效的方法来生成序列,并且没有失去代码的可读性。
1.列表推导式
格式:[ 返回值 循环体 条件 ]
注意:可以没有条件;列表推导式的输出为列表
例1:将字符串中的每个字母大写输出
str1 = "abcdefg"
list1 = [x.upper() for x in str1]
print(list1)
例2:打印50以内能被3整除的数的平方
list2 = [x ** 2 for x in range(1, 50) if x % 3 == 0]
print(list2)
2.集合推导式
格式:{ 返回值 循环体 条件 }
注意:跟列表推导式类似,但集合推导式使用大括号;集合推导式返回结果为集合,所以返回的结果自带去重
例1:输出列表lst中每个数的绝对值
lst = [-1, 1, 2, -2, 4, -5]
s1 = {abs(x) for x in lst}
print(s1)
代码运行结果:
3.字典推导式
格式:{ key:value 循环体 条件 }
注意:字典推导式返回的结果为字典
例1:将字典中的key与value值对调
d1 = {"a": 1, "b": 2}
d2 = {v: k for k, v in d1.items()}
print(d2)
例2:合并大小写对应的value值,将key统一写成小写
d = {'B': 3, 'a': 1, 'b': 6, 'A': 4}
result = {x.lower(): d.get(x.lower(), 0) + d.get(x.upper(), 0) for x in d}
print(result)
运行结果:
二、迭代器
可迭代对象:存储了元素的一个容器对象,实现了__iter__魔术方法。
迭代器对象:实现了__iter__和__next__魔术方法的对象称为迭代器对象。
其中,__iter__方法返回自身(迭代器对象);__next__方法返回下一个值。
如:
str1 = "abc"
iterator_str1 = str1.__iter__()
print(iterator_str1.__next__())
print(iterator_str1.__next__())
print(iterator_str1.__next__())
运行结果:
for语法糖
for先调用可迭代对象的__iter__方法,该方法返回一个迭代器
再对迭代器对象调用__next__方法,不断获取下一个值
直到获取完成抛出StopIteration异常退出
迭代器的优点:懒加载,惰性求值,需要的时候生成,可以节省空间
例:使用迭代器实现阶乘
class factorial():
def __init__(self, stop, num=1, count=1):
self.num = num
self.stop = stop
self.count = count
def __iter__(self):
return self
def __next__(self):
if self.count > self.stop:
raise StopIteration
self.num = self.num * self.count
self.count +=1
return self.num
f = factorial(5)
for i in f:
print(i)
运行结果:输出1-5的阶乘
三、生成器
生成器是迭代器更加优雅的写法,不需要手动实现__iter__和__next__方法。生成器可以用更少的代码来实现迭代器的效果,相比于容器类型更加节省内存。
生成器有两种写法:一种叫生成器表达式,另一种叫生成器函数。
1.生成器表达式-类似于列表推导式
#求1-20之间能被3整除的数的平方
result = (x ** 2 for x in range(1, 21) if x % 3 == 0)
#生成一个生成器对象
print(result)
for i in result:
print(i)
运行结果:
2.生成器函数
包含了yield关键字的函数就叫做生成器函数。yield关键字返回yield关键字后面的内容,保留中间算法,下次继续执行
例:
def get_content():
print("first next".center(30, "*"))
x = 2
yield x
print("second next".center(30, "*"))
y = 3
yield y
print("third next".center(30, "*"))
z = 4
yield z
#类型实例化 g是一个生成器
g = get_content()
print(next(g)) #第一次执行next时,遇到yield就退出,返回yield后面携带的参数,还会记录当前执行的位置
print(next(g)) #第二次执行的时候就会从上一次执行的地方继续执行
print(next(g))
运行结果:
3.应用场景
生成器可以暂时挂起函数,并且保留函数的局部变量等数据,然后在再次调用它的时候,从上次暂停的位置继续执行下去。
(1)大文件处理
一次性读取大文件到内存太占空间,一行一行读效率太慢,可以使用生成器读取固定的字节的数据
#传入文件路径
def read_file(fpath):
#指定一次性读文件的字节数
BLOCK_SIZE = 1024
with open(fpath, 'rb') as f:
while True:
block = f.read(BLOCK_SIZE)
if block:
yield block
else:
return
(2)send向生成器发送值
修改生成器的行为
def send_val():
count = 0
while 1:
val = yield count
if val is not None:
count = val
else:
count += 1
s1 = send_val()
print(next(s1))
print(next(s1))
#使得生成器又从0开始计数
print(s1.send(0))
print(next(s1))
运行结果:
yield与yield from的区别:
def generator1():
#yield后面必须接可迭代对象
yield range(5)
def generator2():
yield from range(5)
#相当于:
#for i in range(5)
# yield i
g1 = generator1()
g2 = generator2()
for i in g1:
print(i)
for i in g2:
print(i)
运行结果: