饮冰三年-人工智能-Python-16Python基础之迭代器、生成器、装饰器
一:闭包
1.1 什么是闭包
- def outerFun():
- name="Aaron" # 外层函数outerFun 中的变量 name
- def innerFun():
- print(name) # 内层函数innerFun 引用了外层函数中的 name
- return innerFun
- f1= outerFun()
- f1()
- # 输出结果 Aaron
内层函数引用外层函数中的变量
- def outerFun():
- nameList=[] # 外层函数outerFun 中的变量 nameList
- def innerFun(name):
- nameList.append(name) # 内层函数innerFun 引用了外层函数中的 nameList,并对其进行修改
- print(nameList)
- return innerFun
- f1= outerFun()
- f1("赵")
- f1("钱")
- f1("孙")
- f2= outerFun()
- f2("Tom")
- f1("李")
- f2("Tony")
- '''
- ['赵']
- ['赵', '钱']
- ['赵', '钱', '孙']
- ['Tom']
- ['赵', '钱', '孙', '李']
- ['Tom', 'Tony']
- '''
外部变量的变化
- 结论:外部变量跟着各自的闭包走,可传递。但闭包之间不受影响
1.2 如何判断函数是否是闭包
- def outerFun():
- name="Aaron" # 外层函数outerFun 中的变量 name
- def innerFun():
- print(name) # 内层函数innerFun 引用了外层函数中的 name
- return innerFun
- f1= outerFun()
- print(f1.__closure__) #输出结果 (<cell at 0x00E7FE10: str object at 0x00E7FDE0>,)
- print(outerFun.__closure__) # 输出结果 None
__closure__
1.3 闭包的特点
- 安全
- 常驻内存
1.4 闭包练习题
- def my_func(*args):
- fs = []
- for i in range(3):
- def func():
- return i * i
- fs.append(func)
- return fs
- fs1, fs2, fs3 = my_func()
- print(type(my_func())) #<class 'list'>
- print(fs1()) #
- print(fs2()) #
- print(fs3()) #
易错题
python解释器开始执⾏之后, 就会在内存中开辟⼀个空间, 每当遇到⼀个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表⽰这个函数存在了, ⾄于函数内部的变量和逻辑, 解释器是不关⼼的. 也就是说⼀开始的时候函数只是加载进来, 仅此⽽已, 只有当函数被调⽤和访问的时候, 解释器才会根据函数内部声明的变量来进⾏开辟变量的内部空间. 随着函数执⾏完毕, 这些函数内部变量占⽤的空间也会随着函数执⾏完毕⽽被清空.
- def my_func(*args):
- fs = []
- for i in range(3):
- def func(_i=i):
- return _i * _i
- fs.append(func)
- return fs
- fs1, fs2, fs3 = my_func()
- print(type(my_func())) #<class 'list'>
- print(fs1()) #
- print(fs2()) #
- print(fs3()) #
正确写法
结论:返回闭包中不要引用任何循环变量,或者后续会发生变化的变量
二:迭代器
1.1 迭代器协议
a:对象必须提供一个next方法,
b:执行方法要么返回迭代中的下一项,要么抛弃一个Stopiteration异常,
c:只能向后不能向前。
1.2 可迭代对象
实现了迭代器协议的对象。(对象内部定义一个__iter__()方法)
1.3 使用迭代器访问对象
检验可迭代对象向 Iterable: 可迭代对象. 内部包含__iter__()函数 Iterator: 迭代器. 内部包含__iter__() 同时包含__next__().
常见的 str,list, tuple, dict, set,都是可以迭代的。
- from collections.abc import Iterable
- from collections.abc import Iterator
- l = [1,2,3]
- l_iter = l.__iter__()
- #检查是否是可迭代的对象
- print(isinstance(l,Iterable)) #True
- print(isinstance(l,Iterator)) #False
- print(isinstance(l_iter,Iterator)) #True
- print(isinstance(l_iter,Iterable)) #True
检验可迭代对象
- st="hello";
- # 先将字符串对象转化为可迭代对象
- iterSt = st.__iter__()
- while True:
- try:
- print(iterSt.__next__())
- except StopIteration:
- # print('迭代完成')
- break
迭代器之for循环模拟
三:生成器
1.1 什么是生成器?生成器的获取方法
使用了 yield 的函数被称为生成器,其实质就是迭代器.
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
1.2 生成器特征
生成器函数:使用yield语句返回结果,在每个结果中间,挂起函数的状态,以便下次从此处继续执行。
不用调用__iter__(),生成器生成的元素直接可调用__next__()方法。
1.3 获取生成器:
- def fun():
- print(111)
- yield 222
- g = fun() #生成器
- print(g); #输出结果:<generator object fun at 0x00EA5D30>
生成器函数
2: 通过生成器推导式来实现生成器
生成器表达式: (结果 for 变量 in 可迭代对象 if 条件筛选)
gen = (i for i in range(1, 10) if i%2==0)
1.4 遍历生成器:
1: 通过__next__()(一次只能获取一个)
2:通过send()(一次只能获取一个,可以传递参数)
3:通过for循环
4:通过list()将其转换为列表
- def fun():
- a = yield 1
- print("接收send传递的值", a)
- b = yield 2
- c = yield 3
- d = yield 4
- e = yield 5
- gen = fun()
- print("通过__next__()获取:", gen.__next__())
- hh=gen.send("")
- print(hh)
- print("结论一:可以看出生成器是惰性机制,也可以叫做是懒加载。用一次给一次,节省内存!")
- for i in gen:
- print(i)
- print("结论二:由于生成器和迭代器类似一旦用过,不能再次使用!")
- print(list(gen))
- ''' 输出结果
- 通过__next__()获取: 1
- 接收send传递的值 12
- 2
- 结论一:可以看出生成器是惰性机制,也可以叫做是懒加载。用一次给一次,节省内存!
- 3
- 4
- 5
- 结论二:由于生成器和迭代器类似一旦用过,不能再次使用!
- []
- '''
遍历生成器
注意:send和__next__()的区别在于,send()可以传递参数。但是send可以给上一个yield的位置传递值, 不能给最后一个yield发送值。同时生成器某些元素用完以后就没有了。
1.5. 其他推导式
列表推导式: [ 结果 for 变量 in 可迭代对象 if 条件 ]
lst = [i for i in range(1, 10) if i%2==0] # [2, 4, 6, 8]
字典推导式:{结果 for 变量 in 可迭代对象 if 条件}
dic = {i-1:i for i in range(1, 10) if i%2==0} #{1: 2, 3: 4, 5: 6, 7: 8}
集合推导式:{结果 for 变量 in 可迭代对象 if 条件}
set = {i%2for i in range(1, 10) } #{0, 1}
1.6. 练习题
1.6.1 人口普查小练习
- {"location":"北京",'count':100}
- {"location":"上海",'count':300}
- {"location":"广州",'count':200}
- {"location":"深圳",'count':400}
人口普查.txt
- # 通过with as 的方式打开文件不用关闭
- def getPeople():
- with open("人口普查","r",encoding="utf-8") as f:
- for i in f:
- yield i
- g = getPeople();
- amount=sum(eval(i)["count"] for i in g)
- h=getPeople()
- for i in h:
- print(eval(i)["location"]+"的人数为:"+ str(eval(i)["count"]) +",占统计总人数的"+str(eval(i)["count"]/amount)+"%")
- '''
- 北京的人数为:100,占统计总人数的0.1%
- 上海的人数为:300,占统计总人数的0.3%
- 广州的人数为:200,占统计总人数的0.2%
- 深圳的人数为:400,占统计总人数的0.4%
- '''
人口.py
1.6.2 生产者消费者模式
- def consumer(name):
- print('我是【%s】,我准备开始吃包子了' %name)
- while True:
- baozi = yield
- print("【%s】很开心的吃掉了【%s】" %(name,baozi))
- def producer():
- c1=consumer('张三')
- c2=consumer("李四")
- c1.__next__()
- c2.__next__()
- for i in range(10):
- if i % 2 == 0:
- c1.send("包子 %s" %i )
- else:
- c2.send("包子 %s" %i)
- producer()
- '''
- 我是【张三】,我准备开始吃包子了
- 我是【李四】,我准备开始吃包子了
- 【张三】很开心的吃掉了【包子 0】
- 【李四】很开心的吃掉了【包子 1】
- 【张三】很开心的吃掉了【包子 2】
- 【李四】很开心的吃掉了【包子 3】
- 【张三】很开心的吃掉了【包子 4】
- 【李四】很开心的吃掉了【包子 5】
- 【张三】很开心的吃掉了【包子 6】
- 【李四】很开心的吃掉了【包子 7】
- 【张三】很开心的吃掉了【包子 8】
- 【李四】很开心的吃掉了【包子 9】
- '''
生产者消费者模式
- # 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个
- # 第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下
- # 的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少。
- # 方法一,递归调用
- def getNum(day,cou=1):
- cou =2 *(cou + 1) ;
- day-=1
- if day==1:
- return cou;
- return getNum(day, cou)
- print(getNum(10))
- # 方法二,递归调用
- def f(n):
- if n ==1:
- return 1
- return (f(n-1)+1)*2
- print(f(10))
- # 方法三,reduce函数
- s=1
- func=lambda x:(x+1)*2
- for x in range(9):
- s=func(s)
- print(s)
猴子吃桃
1.6.3 判断输出结果
- def add(a, b):
- return a + b
- def test():
- for r_i in range(1,4):
- yield r_i
- g=test()
- for n in [2,10]:
- g=(add(n,i) for i in g)
- print(list(g))
- #[21, 22, 23]
- #根据生成器惰性机制,只有在list(g)的时候才开始调用,此时g的内容是什么?
- # 当n=2 时 g=(add(n,i) for i in g) 但是此时仍然没有执行
- # 当n=10 时 g=add(n,i) for i in (add(n,i) for i in g) ),开始执行。
- # 内存计算后得:g=add(n,i) for i in [11,12,13]
- # 再次计算可得:[21,22,23]
生成器,惰性机制
四:装饰器
1.1 什么是装饰器?
装饰器 = 高阶函数 + 函数嵌套 + 闭包
本质就是函数,功能是为其他函数添加附加功能
原则:对修改封闭,对扩展开放
1:不能修改被修饰函数的源代码
2:不能修改被修饰函数的调用方式
- # 装饰器=高阶函数+函数嵌套+闭包
- # 高阶函数:传入参数或输出结果是一个函数
- # 函数嵌套:函数中定义函数
- import time
- def timmer(func):
- def wrapper():
- startTime= time.time()
- func();
- endTime= time.time()
- print("被测试函数一共运行:"+str(endTime-startTime)+"秒")
- return wrapper
- @timmer #语法糖,相当于#test=timmer(test)
- def test():
- time.sleep(0.3);
- print("test函数运行完毕")
- test()
装饰器-计算方法时间
- # 装饰器=高阶函数+函数嵌套+闭包
- # 高阶函数:传入参数或输出结果是一个函数
- # 函数嵌套:函数中定义函数
- import time
- def timmer(func):
- def wrapper(*args,**kwargs):
- startTime= time.time()
- res=func(*args,**kwargs);
- endTime= time.time()
- print("被测试函数一共运行:"+str(endTime-startTime)+"秒")
- return res
- return wrapper
- @timmer #语法糖,相当于#test=timmer(test)
- def test(a,b):
- return a+b
- print(test(100,200))
装饰器-设置参数和返回值
- # 装饰器=高阶函数+函数嵌套+闭包
- # 高阶函数:传入参数或输出结果是一个函数
- # 函数嵌套:函数中定义函数
- import time
- # 添加一个参数,如果参数是n就打n折
- def disCount(n=1):
- def timmer(func):
- def wrapper(*args,**kwargs):
- startTime= time.time()
- res=func(*args,**kwargs)*n;
- endTime= time.time()
- print("今天是国庆节,每位客户打的折扣为:"+str(n*10))
- return res
- return wrapper
- return timmer
- #@timmer #语法糖,相当于#test=timmer(test)
- @disCount(n=0.9)
- def test(a,b):
- return a+b
- print(test(100,200))
闭包,设置参数
饮冰三年-人工智能-Python-16Python基础之迭代器、生成器、装饰器的更多相关文章
- python学习笔记(5)--迭代器,生成器,装饰器,常用模块,序列化
生成器 在Python中,一边循环一边计算的机制,称为生成器:generator. 如: >>> g = (x * x for xin range(10)) >>> ...
- Day4 - Python基础4 迭代器、装饰器、软件开发规范
Python之路,Day4 - Python基础4 (new版) 本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 ...
- Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发
本节大纲 迭代器&生成器 装饰器 基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...
- Python基础4 迭代器、装饰器、软件开发规范
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...
- Python基础-迭代器&生成器&装饰器
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 我现在有个需求,看 ...
- 饮冰三年-人工智能-Python-18Python面向对象
1 类与实例对方法和属性的修改 class Chinese: # 这是一个Chinese的类 #定义一个类属性,又称为静态数据或者静态变量,相当于C#中的static country="Ch ...
- python基础之迭代器生成装饰器
基本概念 1.容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元 ...
- Python(迭代器 生成器 装饰器 递归 斐波那契数列)
1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大优 ...
- 4.python迭代器生成器装饰器
容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元素存储在内存中 ...
随机推荐
- 20165237 2017-2018-2 《Java程序设计》第2周学习总结
20165237 2017-2018-2 <Java程序设计>第2周学习总结 教材学习内容总结 1.标识符第一个字符不能是数字. 2.标识符不能是关键字,也不能是true.false和nu ...
- 【Math for ML】矩阵分解(Matrix Decompositions) (上)
I. 行列式(Determinants)和迹(Trace) 1. 行列式(Determinants) 为避免和绝对值符号混淆,本文一般使用\(det(A)\)来表示矩阵\(A\)的行列式.另外这里的\ ...
- WebBrowser控件的NavigateToString()方法 参数 为中文时乱码问题的解决。
public static string ConvertExtendedASCII(string HTML) { StringBuilder str = new StringBuilder(); ch ...
- 【VMware vSphere】vSphere Data Protection简介
[前言] 还记得一月份左右的时候,万达这边的服务器突然宕机,导致所有的项目不得不停止不说,还损失掉了很多宝贵的数据.为了防止这种情况再次发生,所以近期研究了vSphere Data Protectio ...
- vim7.4+python3配置
基本参考:https://blog.csdn.net/qq_26877377/article/details/80717755 注意几点: (1)关于python的自动补全,不要使用pydiction ...
- k64 datasheet学习笔记50---GPIO
1.前言 GPIO模块支持8bit 16bit 32bit访问,当被配置为GPIO功能时,GPIO数据方向和数据寄存器控制了每个引脚的输出方向和输出数据 不管GPIO配置为何种功能,GPIO输入寄存器 ...
- zynq linux驱动之PL-PS中断【转】
转自:https://blog.csdn.net/h244259402/article/details/83993524 PC:Windows 10 虚拟机:ubuntu 16.04 vivado:2 ...
- Liunx之Centos系统无人值守全自动化安装
作者:邓聪聪 定制centos6.8自动安装ISO光盘 安装系统为centos6.8 (base server),安装方式为全新安装 使用ext4分区格式 安装前可以交互输入root密码,主机名,分区 ...
- hibernate框架学习之数据模型-POJO
Hibernate数据模型用于封装数据,开发时候需要遵从如下规范:1)提供公共无参的构造方法(可使用自动生成的)如果使用投影技术,一定要显式声明公共无参的构造方法2)提供一个标识属性,作为对象的主键, ...
- List<> of struct with property. Cannot change value of property. why?
这个返回如下错误:"Cannot modify the return value of 'System.Collections.Generic.List<MyStruct>.th ...