一:闭包


  1.1 什么是闭包  

    闭包就是内层函数, 对外层函数(非全局)的变量的引⽤.  
  1. def outerFun():
  2. name="Aaron" # 外层函数outerFun 中的变量 name
  3. def innerFun():
  4. print(name) # 内层函数innerFun 引用了外层函数中的 name
  5. return innerFun
  6.  
  7. f1= outerFun()
  8. f1()
  9.  
  10. # 输出结果 Aaron

内层函数引用外层函数中的变量

  1. def outerFun():
  2. nameList=[] # 外层函数outerFun 中的变量 nameList
  3. def innerFun(name):
  4. nameList.append(name) # 内层函数innerFun 引用了外层函数中的 nameList,并对其进行修改
  5. print(nameList)
  6. return innerFun
  7.  
  8. f1= outerFun()
  9. f1("赵")
  10. f1("钱")
  11. f1("孙")
  12. f2= outerFun()
  13. f2("Tom")
  14. f1("李")
  15. f2("Tony")
  16. '''
  17. ['']
  18. ['', '']
  19. ['', '', '']
  20. ['Tom']
  21. ['', '', '', '']
  22. ['Tom', 'Tony']
  23. '''

外部变量的变化

  • 结论:外部变量跟着各自的闭包走,可传递。但闭包之间不受影响

 1.2 如何判断函数是否是闭包 

  使⽤函数名.__closure__返回cell就是闭包。
  1. def outerFun():
  2. name="Aaron" # 外层函数outerFun 中的变量 name
  3. def innerFun():
  4. print(name) # 内层函数innerFun 引用了外层函数中的 name
  5. return innerFun
  6.  
  7. f1= outerFun()
  8.  
  9. print(f1.__closure__) #输出结果 (<cell at 0x00E7FE10: str object at 0x00E7FDE0>,)
  10. print(outerFun.__closure__) # 输出结果 None

__closure__

 1.3 闭包的特点

  • 安全
  • 常驻内存

 1.4 闭包练习题  

  1. def my_func(*args):
  2. fs = []
  3. for i in range(3):
  4. def func():
  5. return i * i
  6. fs.append(func)
  7. return fs
  8. fs1, fs2, fs3 = my_func()
  9. print(type(my_func())) #<class 'list'>
  10. print(fs1()) #
  11. print(fs2()) #
  12. print(fs3()) #

易错题

  python解释器开始执⾏之后, 就会在内存中开辟⼀个空间, 每当遇到⼀个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表⽰这个函数存在了, ⾄于函数内部的变量和逻辑, 解释器是不关⼼的. 也就是说⼀开始的时候函数只是加载进来, 仅此⽽已, 只有当函数被调⽤和访问的时候, 解释器才会根据函数内部声明的变量来进⾏开辟变量的内部空间. 随着函数执⾏完毕, 这些函数内部变量占⽤的空间也会随着函数执⾏完毕⽽被清空.  

  1. def my_func(*args):
  2. fs = []
  3. for i in range(3):
  4. def func(_i=i):
  5. return _i * _i
  6. fs.append(func)
  7. return fs
  8. fs1, fs2, fs3 = my_func()
  9. print(type(my_func())) #<class 'list'>
  10. print(fs1()) #
  11. print(fs2()) #
  12. print(fs3()) #

正确写法

  结论:返回闭包中不要引用任何循环变量,或者后续会发生变化的变量

二:迭代器


  1.1 迭代器协议   

    a:对象必须提供一个next方法

    b:执行方法要么返回迭代中的下一项,要么抛弃一个Stopiteration异常

    c:只能向后不能向前。

 1.2 可迭代对象

    实现了迭代器协议的对象。(对象内部定义一个__iter__()方法)

 1.3 使用迭代器访问对象

    检验可迭代对象向 Iterable: 可迭代对象. 内部包含__iter__()函数   Iterator: 迭代器. 内部包含__iter__() 同时包含__next__().

    常见的 str,list, tuple, dict, set,都是可以迭代的。

  1. from collections.abc import Iterable
  2. from collections.abc import Iterator
  3. l = [1,2,3]
  4. l_iter = l.__iter__()
  5.  
  6. #检查是否是可迭代的对象
  7. print(isinstance(l,Iterable)) #True
  8. print(isinstance(l,Iterator)) #False
  9. print(isinstance(l_iter,Iterator)) #True
  10. print(isinstance(l_iter,Iterable)) #True

检验可迭代对象

  1. st="hello";
  2. # 先将字符串对象转化为可迭代对象
  3. iterSt = st.__iter__()
  4. while True:
  5. try:
  6. print(iterSt.__next__())
  7. except StopIteration:
  8. # print('迭代完成')
  9. break

迭代器之for循环模拟

三:生成器


1.1 什么是生成器?生成器的获取方法    

    使用了 yield 的函数被称为生成器,其实质就是迭代器.

    跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

  1.2 生成器特征    

    生成器函数:使用yield语句返回结果,在每个结果中间,挂起函数的状态,以便下次从此处继续执行。

    不用调用__iter__(),生成器生成的元素直接可调用__next__()方法。

    ⽣成器的惰性机制: 生成器只有在访问的时候才取值.   

  1.3 获取生成器:

    1:  通过生成器函数(含有yield的函数)    
  1. def fun():
  2. print(111)
  3. yield 222
  4. g = fun() #生成器
  5. 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()将其转换为列表   

  1. def fun():
  2. a = yield 1
  3. print("接收send传递的值", a)
  4. b = yield 2
  5. c = yield 3
  6. d = yield 4
  7. e = yield 5
  8.  
  9. gen = fun()
  10. print("通过__next__()获取:", gen.__next__())
  11. hh=gen.send("")
  12. print(hh)
  13. print("结论一:可以看出生成器是惰性机制,也可以叫做是懒加载。用一次给一次,节省内存!")
  14. for i in gen:
  15. print(i)
  16. print("结论二:由于生成器和迭代器类似一旦用过,不能再次使用!")
  17. print(list(gen))
  18.  
  19. ''' 输出结果
  20. 通过__next__()获取: 1
  21. 接收send传递的值 12
  22. 2
  23. 结论一:可以看出生成器是惰性机制,也可以叫做是懒加载。用一次给一次,节省内存!
  24. 3
  25. 4
  26. 5
  27. 结论二:由于生成器和迭代器类似一旦用过,不能再次使用!
  28. []
  29.  
  30. '''

遍历生成器

    注意: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 人口普查小练习  

  1. {"location":"北京",'count':100}
  2. {"location":"上海",'count':300}
  3. {"location":"广州",'count':200}
  4. {"location":"深圳",'count':400}

人口普查.txt

  1. # 通过with as 的方式打开文件不用关闭
  2. def getPeople():
  3. with open("人口普查","r",encoding="utf-8") as f:
  4. for i in f:
  5. yield i
  6. g = getPeople();
  7. amount=sum(eval(i)["count"] for i in g)
  8. h=getPeople()
  9. for i in h:
  10. print(eval(i)["location"]+"的人数为:"+ str(eval(i)["count"]) +",占统计总人数的"+str(eval(i)["count"]/amount)+"%")
  11.  
  12. '''
  13. 北京的人数为:100,占统计总人数的0.1%
  14. 上海的人数为:300,占统计总人数的0.3%
  15. 广州的人数为:200,占统计总人数的0.2%
  16. 深圳的人数为:400,占统计总人数的0.4%
  17. '''

人口.py

    1.6.2 生产者消费者模式

  1. def consumer(name):
  2. print('我是【%s】,我准备开始吃包子了' %name)
  3. while True:
  4. baozi = yield
  5. print("【%s】很开心的吃掉了【%s】" %(name,baozi))
  6.  
  7. def producer():
  8. c1=consumer('张三')
  9. c2=consumer("李四")
  10. c1.__next__()
  11. c2.__next__()
  12. for i in range(10):
  13. if i % 2 == 0:
  14. c1.send("包子 %s" %i )
  15. else:
  16. c2.send("包子 %s" %i)
  17. producer()
  18.  
  19. '''
  20. 我是【张三】,我准备开始吃包子了
  21. 我是【李四】,我准备开始吃包子了
  22. 【张三】很开心的吃掉了【包子 0】
  23. 【李四】很开心的吃掉了【包子 1】
  24. 【张三】很开心的吃掉了【包子 2】
  25. 【李四】很开心的吃掉了【包子 3】
  26. 【张三】很开心的吃掉了【包子 4】
  27. 【李四】很开心的吃掉了【包子 5】
  28. 【张三】很开心的吃掉了【包子 6】
  29. 【李四】很开心的吃掉了【包子 7】
  30. 【张三】很开心的吃掉了【包子 8】
  31. 【李四】很开心的吃掉了【包子 9】
  32. '''

生产者消费者模式

  1. # 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个
  2. # 第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下
  3. # 的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少。
  4.  
  5. # 方法一,递归调用
  6. def getNum(day,cou=1):
  7. cou =2 *(cou + 1) ;
  8. day-=1
  9. if day==1:
  10. return cou;
  11. return getNum(day, cou)
  12. print(getNum(10))
  13. # 方法二,递归调用
  14. def f(n):
  15. if n ==1:
  16. return 1
  17. return (f(n-1)+1)*2
  18. print(f(10))
  19. # 方法三,reduce函数
  20. s=1
  21. func=lambda x:(x+1)*2
  22. for x in range(9):
  23. s=func(s)
  24. print(s)

猴子吃桃

    1.6.3 判断输出结果    

  1. def add(a, b):
  2. return a + b
  3. def test():
  4. for r_i in range(1,4):
  5. yield r_i
  6. g=test()
  7.  
  8. for n in [2,10]:
  9. g=(add(n,i) for i in g)
  10.  
  11. print(list(g))
  12.  
  13. #[21, 22, 23]
  14. #根据生成器惰性机制,只有在list(g)的时候才开始调用,此时g的内容是什么?
  15. # 当n=2 时 g=(add(n,i) for i in g) 但是此时仍然没有执行
  16. # 当n=10 时 g=add(n,i) for i in (add(n,i) for i in g) ),开始执行。
  17. # 内存计算后得:g=add(n,i) for i in [11,12,13]
  18. # 再次计算可得:[21,22,23]

生成器,惰性机制

四:装饰器


1.1 什么是装饰器?

装饰器 = 高阶函数 + 函数嵌套 + 闭包

  本质就是函数,功能是为其他函数添加附加功能

  原则:对修改封闭,对扩展开放

    1:不能修改被修饰函数的源代码

    2:不能修改被修饰函数的调用方式   

  1. # 装饰器=高阶函数+函数嵌套+闭包
  2. # 高阶函数:传入参数或输出结果是一个函数
  3. # 函数嵌套:函数中定义函数
  4. import time
  5. def timmer(func):
  6. def wrapper():
  7. startTime= time.time()
  8. func();
  9. endTime= time.time()
  10. print("被测试函数一共运行:"+str(endTime-startTime)+"秒")
  11. return wrapper
  12. @timmer #语法糖,相当于#test=timmer(test)
  13. def test():
  14. time.sleep(0.3);
  15. print("test函数运行完毕")
  16. test()

装饰器-计算方法时间

  1. # 装饰器=高阶函数+函数嵌套+闭包
  2. # 高阶函数:传入参数或输出结果是一个函数
  3. # 函数嵌套:函数中定义函数
  4. import time
  5. def timmer(func):
  6. def wrapper(*args,**kwargs):
  7. startTime= time.time()
  8. res=func(*args,**kwargs);
  9. endTime= time.time()
  10. print("被测试函数一共运行:"+str(endTime-startTime)+"秒")
  11. return res
  12. return wrapper
  13. @timmer #语法糖,相当于#test=timmer(test)
  14. def test(a,b):
  15. return a+b
  16.  
  17. print(test(100,200))

装饰器-设置参数和返回值

  1. # 装饰器=高阶函数+函数嵌套+闭包
  2. # 高阶函数:传入参数或输出结果是一个函数
  3. # 函数嵌套:函数中定义函数
  4. import time
  5. # 添加一个参数,如果参数是n就打n折
  6. def disCount(n=1):
  7. def timmer(func):
  8. def wrapper(*args,**kwargs):
  9. startTime= time.time()
  10. res=func(*args,**kwargs)*n;
  11. endTime= time.time()
  12. print("今天是国庆节,每位客户打的折扣为:"+str(n*10))
  13. return res
  14. return wrapper
  15. return timmer
  16. #@timmer #语法糖,相当于#test=timmer(test)
  17. @disCount(n=0.9)
  18. def test(a,b):
  19. return a+b
  20.  
  21. print(test(100,200))

闭包,设置参数

饮冰三年-人工智能-Python-16Python基础之迭代器、生成器、装饰器的更多相关文章

  1. python学习笔记(5)--迭代器,生成器,装饰器,常用模块,序列化

    生成器 在Python中,一边循环一边计算的机制,称为生成器:generator. 如: >>> g = (x * x for xin range(10)) >>> ...

  2. Day4 - Python基础4 迭代器、装饰器、软件开发规范

    Python之路,Day4 - Python基础4 (new版)   本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 ...

  3. Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发

    本节大纲 迭代器&生成器 装饰器  基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...

  4. Python基础4 迭代器、装饰器、软件开发规范

    本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...

  5. Python基础-迭代器&生成器&装饰器

    本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 我现在有个需求,看 ...

  6. 饮冰三年-人工智能-Python-18Python面向对象

    1 类与实例对方法和属性的修改 class Chinese: # 这是一个Chinese的类 #定义一个类属性,又称为静态数据或者静态变量,相当于C#中的static country="Ch ...

  7. python基础之迭代器生成装饰器

    基本概念 1.容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元 ...

  8. Python(迭代器 生成器 装饰器 递归 斐波那契数列)

    1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大优 ...

  9. 4.python迭代器生成器装饰器

    容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元素存储在内存中 ...

随机推荐

  1. 20165237 2017-2018-2 《Java程序设计》第2周学习总结

    20165237 2017-2018-2 <Java程序设计>第2周学习总结 教材学习内容总结 1.标识符第一个字符不能是数字. 2.标识符不能是关键字,也不能是true.false和nu ...

  2. 【Math for ML】矩阵分解(Matrix Decompositions) (上)

    I. 行列式(Determinants)和迹(Trace) 1. 行列式(Determinants) 为避免和绝对值符号混淆,本文一般使用\(det(A)\)来表示矩阵\(A\)的行列式.另外这里的\ ...

  3. WebBrowser控件的NavigateToString()方法 参数 为中文时乱码问题的解决。

    public static string ConvertExtendedASCII(string HTML) { StringBuilder str = new StringBuilder(); ch ...

  4. 【VMware vSphere】vSphere Data Protection简介

    [前言] 还记得一月份左右的时候,万达这边的服务器突然宕机,导致所有的项目不得不停止不说,还损失掉了很多宝贵的数据.为了防止这种情况再次发生,所以近期研究了vSphere Data Protectio ...

  5. vim7.4+python3配置

    基本参考:https://blog.csdn.net/qq_26877377/article/details/80717755 注意几点: (1)关于python的自动补全,不要使用pydiction ...

  6. k64 datasheet学习笔记50---GPIO

    1.前言 GPIO模块支持8bit 16bit 32bit访问,当被配置为GPIO功能时,GPIO数据方向和数据寄存器控制了每个引脚的输出方向和输出数据 不管GPIO配置为何种功能,GPIO输入寄存器 ...

  7. zynq linux驱动之PL-PS中断【转】

    转自:https://blog.csdn.net/h244259402/article/details/83993524 PC:Windows 10 虚拟机:ubuntu 16.04 vivado:2 ...

  8. Liunx之Centos系统无人值守全自动化安装

    作者:邓聪聪 定制centos6.8自动安装ISO光盘 安装系统为centos6.8 (base server),安装方式为全新安装 使用ext4分区格式 安装前可以交互输入root密码,主机名,分区 ...

  9. hibernate框架学习之数据模型-POJO

    Hibernate数据模型用于封装数据,开发时候需要遵从如下规范:1)提供公共无参的构造方法(可使用自动生成的)如果使用投影技术,一定要显式声明公共无参的构造方法2)提供一个标识属性,作为对象的主键, ...

  10. List<> of struct with property. Cannot change value of property. why?

    这个返回如下错误:"Cannot modify the return value of 'System.Collections.Generic.List<MyStruct>.th ...