博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
函数进阶三(生成器、生成器表达式、匿名函数)
阅读量:5304 次
发布时间:2019-06-14

本文共 4527 字,大约阅读时间需要 15 分钟。

一. 昨日内容回顾 函数名的运用: 1.特殊的变量 2.函数名可以当作变量赋值 3.函数名可以当作容器类类型的元素 4.函数名可以当作函数的参数 5.函数名可以当作函数的返回值 闭包: 1.内层函数对外层函数(非全局)变量的引用和改变 2.闭包只存在于内层函数中 3.闭包都要逐层返回,最终返回给最外层函数 闭包的特点: 解释器遇到闭包,不会随着函数的结束而结束空间 闭包应用: 装饰器 爬虫 可迭代对象 判断方法: obj "__iter__" in dir(obj) from collections import Iterable isinstance(obj, Iterable) 可迭代对象不能直接取值,必须转化成迭代器取值(__next__) # 迭代器 "__iter__" in dir(obj) from collections import Iterable isinstance(obj, Iterator) while循环模拟for循环
二. 生成器 生成器的本质就是迭代器,生成器是自己用Python代码写的迭代器 生成器函数 生成器表达式 s1 = "ajlsdj" iter(s1) # 这不是手写,是通过Python写的 将一个函数变成生成器函数 只要有 yield 就不是函数,可看成生成器
 
# 生成器函数def func():    print(111)    print(222)    yield 666    # yield "aklsj"# print(func())  # 
返回的是生成器对象ret = func()print(next(ret)) # 这里一个 next 对应一个 yield# print(next(ret)) # 所以这里会报错 StopIteration,除非上面再加个 yield# 111# 222# 666
 

 

# yield 和 return 的共同点和区别# 1. 区别:return 终止函数,而 yield 不会终止生成器函数# 2. 共同点:都会返回一个值,return给函数的执行者返回值,yield是给next()返回值# 示例:def cloth():    for i in range(1, 5001):        print("我写的代码没有bug 衣服%s号" % i)cloth()# 我写的代码没有bug 衣服1号# 我写的代码没有bug 衣服2号# 。。。# 我写的代码没有bug 衣服5000号def cloth1():    for i in range(1, 5001):        yield "有志青年 衣服%s号" % igenor = cloth1()for i in range(1, 101):    print(next(genor))for i in range(1, 51):    print(next(genor))# 有志青年 衣服1号# 有志青年 衣服2号# 。。。# 有志青年 衣服100号# 有志青年 衣服101号# 。。。# 有志青年 衣服149号# 有志青年 衣服150号# 由打印结果可知,生成器会记录上一次运行的位置,再次运行时从上一次位置开始计数

 

# 以下很重要,必须掌握# send nextdef func():    yield 666    yield "abc"    yield "速度"    yield "hxy"genor = func()print(next(genor)) # 666print(next(genor)) # abcprint(genor.send(None)) # send() 必须要有一个参数  # 666print(genor.send(None)) # abc# send 不仅能对应 yield 取值,而且可以给上一个 yield 发送一个值 # 注意前提是上一个 yield 必须赋值给一个变量,否则不会打印 send给它发送的值def func():    count = yield 666    print(count)    s = yield "abc"    print(s)    yield "速度"    yield "hxy"genor = func()print(genor.send(None))  # 666print(genor.send("alex"))  # alex abcprint(genor.send("111"))  # 111 速度# 第一个取值能否用 send 传参?# 不能,比如上面的 print(genor.send(None)) 中的 None 改为 其他的,那么会报错# 因为 send 是给上一个 yield 发送一个值,第一个上面没有值了# 最后一个 yield 永远也得不到 send 传的值。

 

# yield from 将一个可迭代对象变成一个迭代器返回def func():    lst = ["abc", "def", "ghi", "jkl"]    yield lstgenor = func()print(next(genor))  # ['abc', 'def', 'ghi', 'jkl']for i in genor:    print(i)    # ['abc', 'def', 'ghi', 'jkl']def func():    lst = ["abc", "def", "ghi", "jkl"]    yield from lst  # 注意这里与上面的区别genor = func()print(next(genor))  # abcprint(next(genor))  # defprint(next(genor))  # ghiprint(next(genor))  # jklfor i in genor:    print(i)# abc# def# ghi# jkl

 

三. 列表推导式,生成器表达式 列表推导式——用一行代码构建一个简单或较复杂的列表 好处:减少代码量 li = [i for i in range(1, 101)] print(li)
# 列表推导式分三种情况:# 1. 循环模式——[变量(加工后的变量) for 变量 in iterable]# 构建一个列表:['python1期', 'python2期', ...'python25期']print(["python%i期" % i for i in range(1, 26)])# 2. 筛选模式——[变量(加工后的变量) for 变量 in iterable if 条件]# 30以内所有的偶数(两种方法)print([i for i in range(2, 31, 2)])print([i for i in range(1, 31) if i % 2 == 0])# 其他示例print([i for i in range(1, 31) if i % 3 == 0])print([i**2 for i in range(1, 31) if i % 3 == 0])print(["地球%s号" % i for i in range(1, 100, 2)])# 3. 三元模式——循环模式的变异# 个人认为如果要用到 if...else...结构的话就以三元模式把 if...else...写在前面,如果只有一个 if 就用筛选模式把 if 放到后面# 构建一个列表,里面的元素是1-20,能被3整除的元素要替换成*# print("*" if 3 > 2 else 1)print(["*" if i % 3 == 0 else i for i in range(1, 21)])# 将至少含有两个e的名字放到一个列表names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]# 方法一l = []for i in names:    for j in i:        if j.count("e") >= 2:            l.append(j)print(l)# 方法二print([j for i in names for j in i if j.count("e") >= 2])# 列表推导式总结:# 优点:一行搞定,节省代码行数# 缺点:不能用debug模式,列表推导式相对复杂的列表不能用,三层以上效率低也很难写

 

# 生成器表达式# 它与列表推导式写法几乎一样,也有同样的三种模式,只需将[]换成()就可以# 列表推导式print(["python%i期" % i for i in range(1, 26)])# 生成器表达式ret = ("python%i期" % i for i in range(1, 26))for i in ret:    print(i)# 元组没有推导式!!!因为上面的生成器表达式已经用()来表示了# 字典推导式print({i:None for i in range(1, 10)})# {1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None}# 将下面字典的键值对调mcase = {
"a": 10, "b": 34, "c":20, "d":15}print({v:k for k,v in mcase.items()})# 集合推导式# 将{1, -2, 3, -4, 4}的所有元素取平方set1 = {1, -2, 3, -4, 4}print({i**2 for i in set1})# {16, 1, 4, 9} 顺便去重了

 

# 四. 匿名函数lambdadef func(x, y):    return x + yprint(func(3, 4))# 像上面这种只有return 即返回值的函数,可以使用匿名函数 lambda# 匿名函数只能用一行代码表示,冒号前面是参数,后面是返回值func2 = lambda x,y: x + y  # func2就是这个匿名函数的名字print(func2(3, 4))# 写一个匿名函数,需要三个数字参数,返回值为三个数想乘的结果func3 = lambda a, b, c: a * b * cprint(func3(1, 2, 3))

 

转载于:https://www.cnblogs.com/shawnhuang/p/10214120.html

你可能感兴趣的文章
asp.net C#后台实现下载文件的几种方法(全)
查看>>
Web前端开发工程师的具备条件
查看>>
实用Android开发工具和资源精选
查看>>
TileMap
查看>>
JS属性大全
查看>>
java复制文件
查看>>
第一册:lesson seventy nine.
查看>>
GCD的同步异步串行并行、NSOperation和NSOperationQueue一级用dispatch_once实现单例
查看>>
团队作业
查看>>
数据持久化时的小bug
查看>>
mysql中key 、primary key 、unique key 与index区别
查看>>
bzoj2257
查看>>
Linux查看文件编码格式及文件编码转换<转>
查看>>
Leetcode: Find Leaves of Binary Tree
查看>>
Vue 模板解释
查看>>
http://www.bootcss.com/
查看>>
20145308 《网络对抗》 注入shellcode+Return-to-libc攻击 学习总结
查看>>
将多张图片和文字合成一张图片
查看>>
自己动手写ORM(01):解析表达式树生成Sql碎片
查看>>
如何使用USBWebserver在本机快速建立网站测试环境
查看>>