python进阶——高级特性(三)列表生成式、生成器

如有兴趣了解更多请关注我的个人博客https://07xiaohei.com/

(五)列表生成式

1. 概述:

列表生成式是Python中内置的创建列表的方法。

列表生成式基于可迭代对象创建,相较于for循环和if循环,创建快捷(基于C语言实现),代码简介,更具可读性。

但要注意列表生成式对于简单的任务处理更具优势,如果情况复杂,生成难度可能会很高;而且列表生成式会一次性生成全部列表元素,对于大型列表,会导致内存被大量占用。

列表生成式是Python的高级特性体现之一。

2. 语法格式:

[expression for item in iterable if conditional]

expression:expression对应生成式列表的元素,是生成后需要保存的内容,expression通常利用for循环内的变量来计算表示,expression除了使用range循环外,不可省略。

注意:for循环前面的if…else语句是算入表达式之中的,因此for循环前面的if条件语句必须有else来保证能够取到元素。

for循环:语法对应基本的for循环,项item对应了可迭代对象iterable的每一个元素。

允许使用range循环直接表示,可以进行for循环的迭代嵌套创建新的对应关系作为生成式的元素,循环的item可以使用多个变量。

if条件语句:用于判断循环的每个元素是否符合生成的要求标准,用于筛选循环的元素,因此不能在后面的if判断中使用else,否则失去了筛选的作用。

3. 例子:
  • 首先是没有if语句时的列表生成式:

    • 直接使用range迭代快速构建1-10的列表,需要进行list类型转化:
    list_use = list(range(1,11))
    print(list_use,end=" ")
    # 运行结果:
    # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    

    生成一个n*n为元素的1-10的列表:

    list_use = [x*x for x in range(1,11)]
    print(list_use,end=" ")
    # 运行结果:
    # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 
    

    根据给定列表字符串集生成每个字符串的长度:

    list_use = ["ab","cde","fghi","jklmn"]
    list_use2=[len(x) for x in list_use]
    print(list_use2,end=" ")
    # 运行结果:
    # [2, 3, 4, 5]
    
  • 带有if语句时的列表生成式:

    生成30以内的偶数列表:

    list_use = [x for x in range(1,31) if x%2==0]
    print(list_use,end=" ")
    # 运行结果:
    # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30]
    

    生成指定字符串中长度大于3的字符串并全部大写:

    list_use = ["ab","cde","fghi","jklmn"]
    list_use2=[x.upper() for x in list_use if len(x)>3]
    print(list_use2,end=" ")
    # 运行结果:
    # ['FGHI', 'JKLMN'] 
    
  • 多个for循环嵌套的列表生成式:

    全排列的生成:

    list_use1=["a","b","c"]
    list_use2=["1","2","3"]
    list_use=[i+j for i in list_use1 for j in list_use2]
    print(list_use,end=" ")
    # 运行结果:
    # ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3'] 
    
    
  • for循环使用多个变量的列表生成式:

    经常使用的是把dict的键值对按某种逻辑组合成列表的一个元素:

    dict_use={'a':1,'b':2,'c':3,'d':4}
    list_use=[x+str(y) for x,y in dict_use.items()]
    print(list_use,end=" ")
    # 运行结果:
    # ['a1', 'b2', 'c3', 'd4'] 
    

    也可以直接对list的内部元组进行组合:

    list_use1=[("a","1"),("b","2"),("3","c")]
    list_use=[i+j for i,j in list_use1]
    print(list_use,end=" ")
    # 运行结果:
    # ['a1', 'b2', '3c']
    

(六)生成器

对于列表生成式,虽然其运行效率高,代码简洁,但是其一次性生成整个列表,内存消耗代价大,因此,为了节约内存,我们可以使用生成器生成列表。

当然,生成器也可以用于生成其他类型。

1. 概念:

生成器(generator)是一种返回一个值的迭代器,每次从该迭代器取下一个值。

生成器实际上是一种高级迭代器,因此也是可迭代对象,可以使得需要返回一系列元素的函数所需的代码更加的简单和高效,当然也因此只能遍历一次。

生成器通过某种算法,在循环中能够不断计算处下一次需要生成的元素,而不需要创建完整的生成列表,以此来节省空间。

注意,生成器实际上保存的是算法,调用next方法时能够就能够计算出下一个元素的值。

一旦计算到最后一个元素,再次调用next方法,就会抛出StopIteration错误。

生成器有两种表示:生成器表达式和生成器函数。

2. 生成器表达式:

生成器表达式也被称为隐式生成器,语法与推导式基本相同,但要用圆括号来创建生成器,也就是将其[]换成()。

生成器表达式会产生新的生成器对象并返回,不会构建出一个列表进行返回,所以直接输出生成器不会输出对应的结果。

另外,生成器表达式禁止使用yield和yield from表达式(后文会讲)。

例子如下:

将上方例子的[]直接更换为()即可获得生成器,然后使用时直接用next函数或者遍历即可

generator_use =(x*x for x in range(1,5))
print(generator_use)
print(generator_use.__next__(),end=" ")
print(generator_use.__next__(),end=" ")
print(generator_use.__next__(),end=" ")
print(generator_use.__next__(),end=" ")
print(generator_use.__next__(),end=" ")
# 运行结果:
# Traceback (most recent call last):
#   File "D:\pycharmwork\blog_use.py", line 2330, in <module>
#     print(generator_use.__next__(),end=" ")
#           ^^^^^^^^^^^^^^^^^^^^^^^^
# StopIteration
# <generator object <genexpr> at 0x0000016F5D849150>
# 1 4 9 16

generator_use =(x*x for x in range(1,5))
for i in generator_use:
    print(i,end=" ")
#运行结果:
# 1 4 9 16

判断其是否可迭代及其类型:

from collections.abc import *
print(isinstance((x*x for x in range(1,5)),Iterable))
print(type((x*x for x in range(1,5))))
#运行结果如下:
# True
# <class 'generator'>

嵌套for等语法同样可以用于生成器:

list_use1=["a","b","c"]
list_use2=["1","2","3"]
generator_use=(i+j for i in list_use1 for j in list_use2)
for i in generator_use:
    print(i,end=" ")
# 运行结果:
# a1 a2 a3 b1 b2 b3 c1 c2 c3 

dict_use={'a':1,'b':2,'c':3,'d':4}
generator_use=(x+str(y) for x,y in dict_use.items())
for i in generator_use:
    print(i,end=" ")
# 运行结果:
# a1 b2 c3 d4 
3. 生成器函数:

生成器函数类似一般函数,但是额外增加了yield关键字,此时函数返回的是一个生成器对象。

生成器函数和一般函数的区别在于,一般函数的执行流程是顺序执行,当遇到return语句或者执行到最后一行语句时才会返回,而对于生成器函数,遇到yield语句会暂停函数的执行并返回此时的中间结果;一般函数的调用是用函数名显式调用,而生成器函数的调用必须显式或者隐式的使用next语句调用,同时恢复到上一次的yield语句处再往下继续执行。

也就是说,生成器函数能够利用yield语句暂停函数的执行并返回中间元素的对应生成器,并通过next方法恢复函数中断现场,并从暂停的语句处开始继续执行,直到没有yield语句可以运行,此时会引发StopIteration异常。

**yield语句:**语法格式同return语句,只替换关键字。

yield语句负责产生一个返回值并返回,返回后生成器函数会在yield语句处保存函数的内部状态,并挂起函数,直到再次调用,从上一次yield的地方继续执行,沿用上一轮的函数内部变量的状态。

注意,return语句对生成器函数返回值不会产生任何影响,函数返回值仍为生成器对象。如果没有return语句的话,注意函数结束时返回的是StopIteration异常,如果有return语句,函数会立刻停止运行并返回StopIteration异常,而return的返回值只作为异常的说明,而不是函数的返回值。

可以直接显式调用close()来手动关闭生成器函数。

可以用send()向生成器传入外部的值,但注意不能在启动生成器函数时传入。用一个变量接收send的值。

接收语法为:receive变量名 = yield value,这里send的信息会被赋给receive变量名。

send执行时会运行函数,所以如果需要send信息请注意增加yield语句或者修改外部循环。

生成器函数常用于使用生成器的流数据缓冲区。

例子如下:

简单的生成器函数,用next方法显式返回12345序列:

def get_1to5():
    print("启动生成器函数")
    for i in range(1,6):
        print("生成一个新的值中......")
        print("生成成功")
        yield i
generator_use=get_1to5()
print(generator_use.__next__())
print(generator_use.__next__())
print(generator_use.__next__())
print(generator_use.__next__())
print(generator_use.__next__())
print(generator_use.__next__())
# 运行结果:
# Traceback (most recent call last):
#   File "D:\pycharmwork\blog_use.py", line 2387, in <module>
#     print(generator_use.__next__())
#           ^^^^^^^^^^^^^^^^^^^^^^^^
# StopIteration
# 启动生成器函数
# 生成一个新的值中......
# 生成成功
# 1
# 生成一个新的值中......
# 生成成功
# 2
# 生成一个新的值中......
# 生成成功
# 3
# 生成一个新的值中......
# 生成成功
# 4
# 生成一个新的值中......
# 生成成功
# 5

for循环返回:

def get_1to5():
    print("启动生成器函数")
    for i in range(1,6):
        print("生成一个新的值中......")
        print("生成成功")
        yield i
for i in get_1to5():
    print(i)
# 运行结果:
# 启动生成器函数
# 生成一个新的值中......
# 生成成功
# 1
# 生成一个新的值中......
# 生成成功
# 2
# 生成一个新的值中......
# 生成成功
# 3
# 生成一个新的值中......
# 生成成功
# 4
# 生成一个新的值中......
# 生成成功
# 5

return对结果的影响:

def get_1to5():
    print("启动生成器函数")
    for i in range(1,6):
        print("生成一个新的值中......")
        print("生成成功")
        yield i
        return "错误源于完成了函数"
t =get_1to5()
print(t.__next__())
print(t.__next__())
# 运行结果:
# 启动生成器函数
# 生成一个新的值中......
# 生成成功
# 1
# Traceback (most recent call last):
#   File "D:\pycharmwork\blog_use.py", line 2446, in <module>
#     print(t.__next__())
#           ^^^^^^^^^^^^
# StopIteration: 错误源于完成了函数

close显式停止函数运行:

def get_1to5():
    print("启动生成器函数")
    for i in range(1,6):
        print("生成一个新的值中......")
        print("生成成功")
        yield i
generator_use = get_1to5()
print(generator_use.__next__())
print(generator_use.__next__())
generator_use.close()
print(generator_use.__next__())
# 运行结果:
# 启动生成器函数
# 生成一个新的值中......
# 生成成功
# 1
# 生成一个新的值中......
# 生成成功
# 2
# Traceback (most recent call last):
#   File "D:\pycharmwork\blog_use.py", line 2468, in <module>
#     print(generator_use.__next__())
#           ^^^^^^^^^^^^^^^^^^^^^^^^
# StopIteration

def get_1to5():
    print("启动生成器函数")
    for i in range(1,6):
        print("生成一个新的值中......")
        print("生成成功")
        yield i
generator_use = get_1to5()
for i in generator_use:
    print(i)
    if i == 3:
        generator_use.close()
# 运行结果:
# 启动生成器函数
# 生成一个新的值中......
# 生成成功
# 1
# 生成一个新的值中......
# 生成成功
# 2
# 生成一个新的值中......
# 生成成功
# 3

send发送信息和receive接收信息:

def get_1to5():
    for i in range(1,6):
        val =yield i
        print("接收信息"+str(val))

generator_use = get_1to5()
i = generator_use.__next__()
print(i)
while True:
    i = generator_use.send(i*i)
    print(i)
    if i == 5:
        break
# 运行结果:
# 1
# 接收信息1
# 2
# 接收信息4
# 3
# 接收信息9
# 4
# 接收信息16
# 5

最后用生成器函数设计一个杨辉三角:

def Triangle():
    result=[1]
    result_next = [1,1]
    while True:
        yield result
        result = result_next
        result_next=[1]+ [result_next[i]+result_next[i+1] for i in range(len(result_next)-1)]+[1]
for i in Triangle():
    print(i)
    if(len(i)==10):
        break
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaohei07

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值