一:闭包


  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 如何判断函数是否是闭包 

  使⽤函数名.__closure__返回cell就是闭包。
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 获取生成器:

    1:  通过生成器函数(含有yield的函数)    
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))

闭包,设置参数

最新文章

  1. Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理5
  2. JAVA中的聚集和组合的区别和联系
  3. c#汉字与编码之间的转换(输出十六进制)
  4. java 从jar包中读取资源文件
  5. 导出函数结构 EXPORT_DIRECTORY
  6. vim 小技巧总结
  7. golang做的邮件服务器
  8. 构建自己的Java并发模型框架
  9. php浏览历史记录的方法
  10. Bootstrap按钮插件
  11. Problem K
  12. UVa 11988破损的键盘
  13. img加载卡顿,解决办法
  14. Counting Sort(Java)
  15. zookeeper使用详解(命令、客户端、源码)
  16. .gitlab-ci.yml 配置文件,知识点
  17. R语言读取Hive数据表
  18. [转]用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口
  19. C语言变量的类型和存储位置
  20. HTML不常用的表单属性-fieldset

热门文章

  1. Android软键盘在清单文件中所有配置含义
  2. pt-table-checksum 使用方法【转】
  3. Win2008R2配置WebDeploy发布网站
  4. Unity3D ParticleSystem粒子系统
  5. vuex之 mapState, mapGetters, mapActions, mapMutations 的使用
  6. HDU 5033
  7. 【原创】运维基础之OpenResty
  8. HomeBrew 安转beta版软件
  9. AMD-requireJS
  10. linq基本操作