一:闭包


  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))

闭包,设置参数

饮冰三年-人工智能-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. Photoshop CS6打开图片后看不到怎么办

    https://jingyan.baidu.com/album/54b6b9c0d45c632d583b4793.html

  2. bootstrap中的明星属性

    1.明星属性 bootstrap中的明星属性 class='text-nowrap' 2.明星代码 $(window).resize(function () { location.reload(); ...

  3. 记录一下putty的pscp的用法【转】

     转自 记录一下putty的pscp的用法 - 刘荣星的博客 https://www.liurongxing.com/how-use-the-putty-and-pscp.html 以前一直用Secu ...

  4. Windows PowerShell 入門(4)-変数と演算子

    Windows PowerShellにおける変数と演算子の使用方法について学びます.今回は代表的な演算子として.算術演算子.代入演算子.論理演算子.比較演算子.範囲演算子.置換演算子.ビット演算子.型 ...

  5. webpack打包生成多个vendor的配置方法

    用webpack打包项目的时候,一般喜欢把一些公用的库打包的vendor.js里面,比如像react,react-router,redux等. 随着引入的库越来越多,vendor文件也变得越来越大,于 ...

  6. NLog类库使用探索——详解配置

    1 配置文件的位置(Configuration file locations) 通过在启动的时候对一些常用目录的扫描,NLog会尝试使用找到的配置信息进行自动的自我配置. 1.1 单独的*.exe客户 ...

  7. 021_mac提效神奇Alfred

    一.破解版下载 (1)https://pan.baidu.com/s/1Kb0HtybvdA1yzHeOWUFM_w 提取码:9tq2 Reference:https://www.jianshu.co ...

  8. zabbix3监控php-fpm的状态

    php-fpm和nginx一样内建了一个状态页,对于想了解php-fpm的状态以及监控php-fpm非常有帮助 . 启用php-fpm状态功能 [root@node1:~]# vim /usr/loc ...

  9. 8-Images

    HTML Image Tags Tag Description <img> Defines an image <map> Defines an image-map <ar ...

  10. C++ sizeof()练习

    class A { int a; short b; int c; char d; }; class B { double a; short b; int c; char d; }; 在32位机器上用g ...