推导式
概述
Python中的推导式是一种快速、简洁的数据结构创建方式,不需要手动创建数据结构中的每一个元素,类似于给出一个规律
,python会根据这个规律自动填充数据结构。支持有列表推导式
、字典推导式
、集合推导式
。
列表推导式
嵌套if语句
创建一个包含1-10
中的所有偶数的列表,常规的做法可能是:
# 先创建一个空列表
even_numbers = []
# 然后遍历1-101,找到其中的偶数
for x in range(1, 11):
if x & 1 == 0:
# 最后将找到的偶数添加到列表中
even_numbers.append(x)
print(even_numbers)
# 输出结果
[2, 4, 6, 8, 10]
推导式依然遵循这个计算逻辑,但是写法不同,更为简介:
even_numbers2 = [x for x in range(1, 11) if x & 1 == 0]
print(even_numbers2)
# 输出结果
[2, 4, 6, 8, 10]
其计算过程依然是先遍历range(1-11)
,然后每次遍历的值都会和1进行按位与,如果是0,就将值也就是x放入列表中,也就是推导式开头的x。
另外,还可以对取得的值x再进行处理,比如每个值都加2
even_numbers3 = [x+2 for x in range(1, 11) if x & 1 == 0]
print(even_numbers3)
# 输出结果
[4, 6, 8, 10, 12]
嵌套循环
Python中也运行对推导式进行循环嵌套
比如:计算99乘法表
multiplication_table = [f{x} x {y} = {x * y} for x in range(1, 10) for y in range(x, 10)]
print(multiplication_table)
# 输出结果
['1 x 1 = 1', '1 x 2 = 2', '1 x 3 = 3', '1 x 4 = 4', '1 x 5 = 5', '1 x 6 = 6', '1 x 7 = 7', '1 x 8 = 8', '1 x 9 = 9', '2 x 2 = 4', '2 x 3 = 6', '2 x 4 = 8', '2 x 5 = 10', '2 x 6 = 12', '2 x 7 = 14', '2 x 8 = 16', '2 x 9 = 18', '3 x 3 = 9', '3 x 4 = 12', '3 x 5 = 15', '3 x 6 = 18', '3 x 7 = 21', '3 x 8 = 24', '3 x 9 = 27', '4 x 4 = 16', '4 x 5 = 20', '4 x 6 = 24', '4 x 7 = 28', '4 x 8 = 32', '4 x 9 = 36', '5 x 5 = 25', '5 x 6 = 30', '5 x 7 = 35', '5 x 8 = 40', '5 x 9 = 45', '6 x 6 = 36', '6 x 7 = 42', '6 x 8 = 48', '6 x 9 = 54', '7 x 7 = 49', '7 x 8 = 56', '7 x 9 = 63', '8 x 8 = 64', '8 x 9 = 72', '9 x 9 = 81']
这里的循环嵌套就相到于:
multiplication_table2 = []
for x in range(1, 10):
for y in range(x, 10):
multiplication_table2.append(f{x} * {y} = {x * y})
print(multiplication_table2)
此外,推导式还支持字典、集合
字典推导式
{} 表示字典,其中写推导式
创建一个字典,key是1-5的数字,值是key的平方
squares_dict = {x: x**2 for x in range(1, 5)}
print(squares_dict)
# 输出结果
{1: 1, 2: 4, 3: 9, 4: 16}
字典推导式中不适合嵌套循环,因为字典的key是唯一的。
集合推导式
例如:提取字符串中的唯一字符
unique_chars = {char for char in hello world}
print(unique_chars)
# 输出结果
{'h', 'r', 'd', 'w', 'o', 'e', 'l', ' '}
元组()没有推导式,()用于生成式。
生成式
如果说推导式是根据规律自动填充数据,那么生成式则是规律本身,因为它是惰性的不会一次性生成所有元素,而是按需生成,每执行一次则生成一个元素。生成式本身是一个可迭代对象。
语法:
(表达式 for
变量in
可迭代对象 if
条件)
( )表示生成式, 如果换成 [ ]则表示列表推导式。
# 生成 1~10 的平方,但不会一次性存入列表
squares_gen = (x**2 for x in range(1, 10))
print(squares_gen) # 输出的是生成器对象
# 输出结果
<generator object=""> at 0x102273bc0></generator>
next() 迭代取值
next() 函数接收一个生成器对象,每执行一次则返回迭代器的下一个元素对象。
# 生成 1~10 的平方,但不会一次性存入列表
squares_gen = (x**2 for x in range(1, 10))
print(squares_gen) # 输出的是生成器对象
for i in range(1, 3):
print(f第{i}次: {next(squares_gen)})
需要注意的是
生成式
只能被遍历一次,当遍历结束后生成式
就会耗尽,无法再次使用。等待被 垃圾回收(Garbage Collection),或者手动删除引用后销毁。
生成式更节省内存
由于生成式不会一次性生成所有数据,而是按需生成,相比推导式更节省内存。
测试:
生成1-10000的序列,检查内存占用
# 推导式
list_squares = [x for x in range(10000)]
print(sys.getsizeof(list_squares), bytes)
# 输出结果
85176 bytes
# 生成式
gen_squares = (x for x in range(10000))
print(sys.getsizeof(gen_squares), bytes)
# 输出结果
104 bytes
生成式与列表、字典、集合的转换
转换为列表,list()函数
gen_even_numbers = (x for x in range(1, 11) if x & 1 == 0)
list_even_numbers = list(gen_even_numbers)
转换为集合,set()函数
unique_chars = (char for char in hello word)
set_unique_chars = set(unique_chars)
转换为字典,dict()函数
square_dict = dict({x: x**2 for x in range(4)})
这里转换的过程就是就生成式迭代的过程,也就意味着生成式已经被消费了,无法继续使用。
# 反转字典
students = {Alice: 85, Bob: 92, Charlie: 78}
reversed_dict = dict((v, k) for k, v in students.items())
生成器
生成器可以看做加强版的生成式,本质上是一个函数,借助 yield
关键字变成生成器,可以按需生成数据节省内存。
与生成式不同的是,它可以实现复杂的逻辑如状态保存、多步计算,并且生成器可以进行复用。
例如:
# 定义生成器gen
def gen():
for i in range(1, 10):
if i & 1 == 0:
yield i
# 赋值给多个对象,实现复用
g = gen()
h = gen()
for x in range(4):
print(next(g))
for x in range(4):
print(next(h))
# 输出结果
2
4
6
8 # g耗尽
2
4
6
8 # h耗尽
关于yield
:
yield
是一个 关键字,用于在 生成器(Generator) 中 暂停函数的执行,并返回一个值,但不会终止函数。当生成器的 next()
方法被调用时,函数会从 yield
语句暂停的地方继续执行。
生成器中可以使用多个yield
。
示例:
def my_generator():
print(执行第一步)
yield 1 # 第一次调用 next(),返回 1 后暂停,等待下次调用
print(执行第二步)
yield 2 # 第二次调用 next(),返回 2 后暂停,等待下次调用
print(执行第三步)
yield 3 # 第三次调用 next(),返回 3 后暂停,等待下次调用
gen = my_generator() # 创建生成器对象
print(next(gen)) # 执行到 yield 1
print(next(gen)) # 继续执行到 yield 2
print(next(gen)) # 继续执行到 yield 3
print(next(gen)) # 抛出 StopIteration 异常
生成器暂停后,可以调用 gen.close()
手动终止生成器或者 del gen
删除引用。
生成器一旦终止,之后再调用 next()
方法,则会抛出 StopIteration
异常。
yield from嵌套生成器
def sub_gen():
print(in sub 1)
yield a # 2
print(in sub 2)
yield b # 3
def main_gen():
print(in main 1)
yield A # 1
print(in main 2)
yield from sub_gen()
print(in main 3)
yield B # 4
g = main_gen()
for i in range(1, 6):
print(f第{i}次执行, **20)
print(next(g))
# 执行结果
第1次执行 ********************
in main 1
A
第2次执行 ********************
in main 2
in sub 1
a
第3次执行 ********************
in sub 2
b
第4次执行 ********************
in main 3
B
第5次执行 ********************
StopIteration
yield from
让 main_gen()
直接返回 sub_gen()
产生的值,同样的遇到 yield
都会暂停执行。
https://www.hugbg.com/archives/3855.html
评论