python中“生成器”、“迭代器”、“闭包”、“装饰器”的深入理解

一、生成器

1、生成器定义:在python中,一边循环一边计算的机制,称为生成器:generator.

a. 语法上和函数类似:生成器函数和常规函数几乎是一样的。它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值。

b. 自动实现迭代器协议:对于生成器,python会自动实现迭代器协议,以便应用到迭代中(如for循环,sum函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用它的next方法,并且,在没有值可以返回的时候,生成器自动产生StopIteration异常

c. 状态挂起:生成器使用yield语句返回一个值。yield语句挂起该生成器函数的状态,保留足够的信息,以便以后从它离开的地方继续执行

2、生成器优点:

节约内存。python在使用生成器时对延迟操作提供了支持。所谓延迟,是指在需要的时候才产生结果,而不是立即产生结果。这样在需要的时候才去调用结果,而不是将结果提前存储起来要节约内存。比如用列表的形式存放较大数据将会占用不少内存。这是生成器的主要好处。比如大数据中,使用生成器来调取数据结果而不是列表来处理数据,因为这样可以节约内存。

l 迭代到下一次的调用时,所使用的参数都是第一次所保留下的。

3、在python中,有两种创建生成器的方式:

(1)生成器表达式:类似与列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表。

使用列表推导,将会一次返回所有结果:

  1. list1 = [i**2 for i in range(5)]
  2. print(list) #[0,1,4,9,16]

将列表推导的中括号,替换成圆括号,就是一个生成器表达式:

  1. list1 = (i**2 for i in range(5))
  2. print(list1)
  3. for x in range(5):
  4. print(next(li))

输出结果为:

  1. <generator object <genexpr> at 0x0C87B5D0>
  2. 0
  3. 1
  4. 4
  5. 9
  6. 16

注意:创建完成生成器后,可以使用next()来调用生成器的数据结果,每调用一次返回一个值,直到调用结束。调用结束后list1中为空的,不在有任何值。要想使用它,只能重新创建新的生成器。(生成器表达式的第四行代码也可以改成:print(x).)

(2)生成器函数

常规函数定义,但是使用yield语句而不是return语句返回结果。yield语句每次返回一个结果,但每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行。

我们下面来看一个例子。下面为一个可以无穷生产奇数的生成器函数。

  1. def numall():
  2. n=1
  3. while True:
  4. yield n
  5. n += 2
  6.  
  7. demo_numall = numall()
  8. count = 0
  9. for i in demo_numall:
  10. if count >= 5:
  11. break
  12. print(i)
  13. count += 1

输出结果为:

  1. 1
  2. 3
  3. 5
  4. 7
  5. 9

上面的函数中,yield是必备的,当一个普通函数中包含yield时,系统会默认为是一个generator。

再举一个例子。使用生成器函数来生成斐波纳契数列

  1. def fibn(times):
  2. n,a,b = 0,0,1
  3. while n < times:
  4. yield b
  5. a,b = b,a+b
  6. n += 1
  7. f = fibn(5)
  8. for i in f:
  9. print(i)

输出结果为:

  1. 1
  2. 1
  3. 2
  4. 3
  5. 5

生成器的两种方法:__next__() 和 send() 方法。

其中,__next__() 方法和next的作用是一样的。如下所示。

  1. def fibn(times):
  2. n,a,b = 0,0,1
  3. while n < times:
  4. yield b
  5. a,b = b,a+b
  6. n += 1
  7. f = fibn(5)
  8. for i in range(5):
  9. print(f.__next__())

输出结果为:

从上面的程序中可以看出,f._next_() 和 next(f) 是作用是一样的。

下面再来看看send() 方法的使用。

  1. def fibn(times):
  2. n,a,b = 0,0,1
  3. while n < times:
  4. temp = yield b
  5. print(temp)
  6. a,b = b,a+b
  7. n += 1
  8. f = fibn(5)
  9. print(f.__next__())
  10. print(f.send("1230"))
  11. print(f.send("abd"))

输出结果为:

  1. 1
  2. 1230
  3. 1
  4. abd
  5. 2

从上面代码可以看出:使用send()时,必须在yield前面加上一个变量,并打印这个变量。在调用send()方法时其前面需要至少使用一次next()或__next__()方法,因为生成器不可以在使用之前导入任何非None参数。由此可以知道,send()是用来向生成器中导入参数并返回该参数的,与该参数一起返回的还有生成器中原先保存的数据。

4、示例

首先,生成器的好处是延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用。在大数据运行时,会很节省内存空间

  1. a=sum([i for i in range(1000000000)])
  2. print(a)
  3.  
  4. b=sum(i for i in range(1000000000))
  5. print(b)

二、迭代器

迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历位置的对象。迭代器只能往前不能后退。

1、可迭代对象(Iterable):— 集合数据类型,如 list 、tuple、dict、set、str 等;— 生成器和带yield 的generator function

2、判断对象可迭代:

  1. from collections import Iterable
  2.  
  3. isinstance([ ],Iterable) #True

  如上,命令行模式下,先导入Iterable模块,然后输入isinstance([ ],Iterable),括号中前面为待判断的对象,结果以布尔类型结束(True或False),列表是可迭代对象,因此返回True。注意:整数是不可迭代对象。

3、迭代器:迭代器是可以被next() 函数调用并不断返回下一个值的对象称为迭代器。因此生成器是迭代器的子类,但是注意集合类型的可迭代对象不是迭代器。

  1. from collections import Iterator
  2.  
  3. isinstance((x for x in range(10)),Iterator)

这两行代码是用来判断是否为迭代器的,返回True或False。

iter()函数:将可迭代对象转换成迭代器。

三、闭包

1、闭包:内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。

闭包三要素: 1、嵌套函数 2、变量的引用 3、返回内部函数

定义闭包时必须满足这三个要素。

  1. def test(num):
  2. def test_in(num_in): #1.嵌套函数
  3. sum = num +num_in #2.内部引用外部变量
  4. return sum,num,num_in
  5. return test_in #3.返回内部函数
  6. Test = test(10)
  7. print(Test)
  8. print(Test(10))

输出结果为:

  1. <function test.<locals>.test_in at 0x0C503030>
  2. (20, 10, 10)

2、闭包应用

#求一元一次方程的值(y=a*x+b),输入x,求y

  1. def fun(a,b):
  2. def fun_in(x):
  3. return a*x+b
  4. return fun_in
  5. f = fun(3,5)
  6. print(f(2))
  7. print(f(3))

输出结果为:

  1. 11
  2. 14

上面的函数中,利用闭包来求一元一次方程的值,更方便,直接输入x的值即可求出对应的y的值。因为这利用了闭包可以记住外部函数的参数的特性。

global修改全局变量

  1. x = 2
  2. def outer():
  3. x = 0
  4. def inner():
  5. # global x
  6. x = 1
  7. print(x)
  8. print(x)
  9. return inner
  10. #调用
  11. outer()
  12. print(x)

运行结果如下:

  1. 0
  2. 1
  3. 1

注意:nonlocal此时是对嵌套变量也就是x = 2 进行操作处理。

四、装饰器

1、装饰器(decorator:装饰器其实就是一个闭包,把一个函数当作参数然后返回一个替代版函数。

装饰器有2个特性:

1、可以把被装饰的函数替换成其他函数

2、可以在加载模块时候立即执行

2、装饰器的功能

Ø 引入日志

Ø 函数执行时间统计

Ø 执行函数前预备处理

Ø 执行函数后清理功能

Ø 权限校验等场景

Ø 缓存

3、装饰器的分类

装饰器可分为对有无参数函数进行装饰的装饰器和对有无返回值函数进行装饰的装饰器,组合起来一共有4种。即:装饰器对无参数无返回值的函数进行装饰,装饰器对无参数有返回值的函数进行装饰,装饰器对有参数无返回值的函数进行装饰,装饰器对有参数有返回值的函数进行装饰。

A、装饰器对无参数函数进行装饰

  1. def makeRedColor(fn):
  2. def wrapper():
  3. return "\033[31m" + fn()
  4. return wrapper
  5.  
  6. def makeBoldFont(fn):
  7. def wrapper():
  8. return "\033[32m " + fn()
  9. return wrapper
  10.  
  11. @makeRedColor
  12. def test1():
  13. return "hello world - 1"
  14.  
  15. @makeBoldFont
  16. def test2():
  17. return "hello world - 2"
  18.  
  19. @makeRedColor
  20. @makeBoldFont
  21. def test3():
  22. return "hello world - 3"
  23.  
  24. print(test1())
  25. print(test2())
  26. print(test3())

输出结果为:

注意:对一个函数可以同时使用多个装饰器,装饰顺序由内而外。

B、装饰器对有参数函数进行装饰

  1. def deco(fn):
  2. def wrapper(a,b): #内部函数的参数必须和被装饰的函数保持一致
  3. print("和值为:",end='')
  4. fn(a,b)
  5. return wrapper
  6. @deco
  7. def sum1(a,b):
  8. print(a+b)
  9.  
  10. sum1(10,15)

输出结果为:

和值为:25

当装饰器装饰有参数的函数时,装饰器内部的函数也必须带有和其相同的参数,因为被装饰的参数会被当成参数传进装饰器的内部函数中,如果两者的参数不一致,会报错。

C、装饰器对不定长参数函数进行装饰

  1. import time
  2. def deco(func):
  3. def wrapper(*arg,**kwargs):
  4. print("{}在{}被调用执行".format(func.__name__,time.ctime()))
  5. func(*arg,**kwargs)
  6. return wrapper
  7.  
  8. @deco
  9. def sum1(a,b,c):
  10. print(a+b+c)
  11.  
  12. @deco
  13. def sum2(a,b):
  14. print(a+b)
  15.  
  16. sum1(1,2,3)
  17. time.sleep(2)
  18. sum2(5,3)
  19. time.sleep(2)
  20. sum1(1,2,3)
  21. time.sleep(2)

输出结果为:

  1. sum1Tue Dec 4 11:45:56 2018被调用执行
  2. 6
  3. sum2Tue Dec 4 11:45:58 2018被调用执行
  4. 8
  5. sum1Tue Dec 4 11:46:00 2018被调用执行
  6. 6

D、装饰器对有返回值的函数进行装饰

  1. import time
  2. def deco(func):
  3. def wrapper(*arg,**kwargs):
  4. print("{}在{}被调用执行".format(func.__name__,time.ctime()))
  5. return func(*arg,**kwargs)
  6. return wrapper
  7.  
  8. @deco
  9. def sum1(a,b,c):
  10. print(a+b+c)
  11.  
  12. @deco
  13. def test():
  14. print("太阳当空照,花儿对我笑")
  15.  
  16. sum1(1,2,3)
  17. test()

输出结果为:

  1. sum1Tue Dec 4 11:49:10 2018被调用执行
  2. 6
  3. testTue Dec 4 11:49:10 2018被调用执行
  4. 太阳当空照,花儿对我笑

这个的装饰器是一个万能的装饰器,因为其可以用来装饰任何函数,包括有无参数函数和有无返回值函数。

实例:

模拟Django 注册登录装饰器

  1. import time
  2. a = ['while','for','django']
  3. def outer(func):
  4. def inner(name):
  5. func(name)
  6. print('开始判断有没有登录?')
  7. time.sleep(2)
  8. if name in a:
  9. print('{}已经登录成功,请尽情访问'.format(name))
  10. time.sleep(1)
  11. else:
  12. print('{}没有登录,没有权限访问'.format(name))
  13. time.sleep(1)
  14. return inner
  15. @outer
  16. def login(name):
  17. print('{}要浏览'.format(name))
  18. login('for')

执行结果:

  1. for要浏览
  2. 开始判断有没有登录?
  3. for已经登录成功,请尽情访问

python中“生成器”、“迭代器”、“闭包”、“装饰器”的深入理解的更多相关文章

  1. python中函数总结之装饰器闭包

    1.前言 函数也是一个对象,从而可以增加属性,使用句点来表示属性. 如果内部函数的定义包含了在外部函数中定义的对象的引用(外部对象可以是在外部函数之外),那么内部函数被称之为闭包. 2.装饰器 装饰器 ...

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

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

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

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

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

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

  5. python 函数名 、闭包 装饰器 day13

    1,函数名的使用. 函数名是函数的名字,本质就是变量,特殊的变量.函数名()加括号就是执行此函数. 1,单独打印函数名就是此函数的内存地址. def func1(): print(555) print ...

  6. python基础之迭代器、装饰器、软件开发目录结构规范

    生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大 ...

  7. Python中生成器,迭代器,以及一些常用的内置函数.

    知识点总结 生成器 生成器的本质就是迭代器. 迭代器:Python中提供的已经写好的工具或者通过数据转化得来的. 生成器:需要我们自己用Python代码构建的 创建生成器的三种方法: 通过生成器函数 ...

  8. python基础语法_9-1闭包 装饰器补充

    1.闭包的概念 closure:内部函数中对enclosing作用域的变量进行引用,外部函数返回内部函数名   2.函数实质与属性 函数是一个对象:在内存中有一个存储空间 函数执行完成后内部变量回收: ...

  9. 【Python入门学习】闭包&装饰器&开放封闭原则

    1. 介绍闭包 闭包:如果在一个内部函数里,对在外部作用域的变量(不是全局作用域)进行引用,那边内部函数被称为闭包(closure) 例如:如果在一个内部函数里:func2()就是内部函数, 对在外部 ...

  10. Python中的多个装饰器装饰一个函数

    def wrapper1(func1): def inner1(): print('w1 ,before') func1() print('w1 after') return inner1 def w ...

随机推荐

  1. listen 65

    Don't Treat Old Gadgets Like Garbage Did you get a new tablet or computer this holiday season? A new ...

  2. unity3d: how to display the obj behind the wall

    透墙显示,遮挡显示,使用ztest Tags { "Queue"="Overlay+1" "RenderType"="Transp ...

  3. codeforces 566D D. Restructuring Company(并查集)

    题目链接: D. Restructuring Company time limit per test 2 seconds memory limit per test 256 megabytes inp ...

  4. 淘宝双十一页面(Flexible)

    以下demo点我下载 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  5. hdu3739 Anti LIS[最小割]

    长度为 n≤1000 的数列 ai,其中最长上升子序列的长度为 s.至少删去多少数使得最长上升子序列的长度小于 s. 其实这题和那个求有多少不重叠LIS是一样答案的. 先放个图. 图丑别说我. 原网络 ...

  6. 「LuoguP1429」 平面最近点对(加强版)

    题目描述 给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的 输入输出格式 输入格式: 第一行:n:2≤n≤200000 接下来n行:每行两个实数:x y, ...

  7. 制定一套适合自己团队的GITflow标准化工作流

    Git作为分布式代码管理的“当红炸子鸡”,被越来越多团队使用.当团队多个人员在同一个Git仓库上进行代码开发,没有一套标准化流程,将会引起代码管理的混乱,上线流程的迷茫,影响工作效率.制定一套适合自己 ...

  8. HL7 ADT Message Sample

    http://pixpdqtests.nist.gov:8080/#tests%2Fdriver%2Fversion.htm 可以打开上述连接, 选中version和actor, 然后获取对于samp ...

  9. 11 Vue学习 headtop

    1: HeaderTop.vue : 面包屑:el-breadcrumb 定义面包屑, separator是分隔符.       el-breadcrumb-item: 是面包屑中用 分隔符 分开的多 ...

  10. A Beginner's Guide to HTTP and REST

    http://code.tutsplus.com/tutorials/a-beginners-guide-to-http-and-rest--net-16340 Hypertext Transfer ...