迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

1|1可迭代对象

以直接作用于 for 循环的数据类型有以下几种:

一类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等;

一类是 generator ,包括生成器和带 yield 的generator function。

这些可以直接作用于 for 循环的对象统称为可迭代对象: Iterable 。

1|2判断是否可以迭代

可以使用 isinstance() 判断一个对象是否是 Iterable 对象:

from collections import Iterable

isinstance([],Iterable)

# True

isinstance({},Iterable)

# True

isinstance(123,Iterable)

# False

isinstance((x for x in range(10)),Iterable)

# True

1|3什么是迭代器

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

可以使用 isinstance() 判断一个对象是否是 Iterator 对象:

from collections import Iterator

isinstance([],Iterator)

False

isinstance({},Iterator)

False

isinstance((x for x in range(10)),Iterator) #

True

生成器都是迭代器。

1|4iter()函数

虽然list 、 tuple 、 dict 、 set 、 str 等是可迭代对象,但他们不是迭代器。可以通过iter()函数把可迭代对象编程迭代器。

isinstance(iter([]),Iterator)

# True

isinstance(iter({}),Iterator)

# True

isinstance(iter("asdf"),Iterator)

# True

1|5总结:

凡是可作用于 for 循环的对象都是 Iterable 类型。

凡是可作用于 next() 函数的对象都是 Iterator 类型。

集合数据类型如 list 、 dict 、 str 等是 Iterable 但不是 Iterator ,不过可以通过 iter() 函数获得一个 Iterator 对象。

2|0生成器

2|1什么是生成器

我们可以通过列表生成式来创建一个列表,但是收到内存的限制,列表的容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

1|1修改列表推导式创建生成器的方法

最简单的方法是把列表生成式中的 [ ] 改成 ( ) 就好了。

a = [x for x in range(10)]

print(a) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

b = (x for x in range(10))

print(b) # at 0x03387DB0>

如何遍历生成器

我们发现生成器不是能直接打印出来的,我们可以通过next()函数来获得生成器的下一个返回值。

生成器保存的是算法,每次调用 next(G) ,就计算出 G 的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出 StopIteration 的异常。

**使用next() 或者__next __():**

print(next(b))

# 0

print(next(b))

# 1

print(next(b))

# 2

print(next(b))

# 3

print(next(b))

# 4

print(next(b))

# 5

print(b.__next__())

# 6

print(b.__next__())

# 7

print(b.__next__())

# 8

print(b.__next__())

# 9

print(b.__next__())

# Traceback (most recent call last):

# File "", line 2, in

# StopIteration

那么有什么简单的方法呢?因为生成器是可迭代对象,也可以使用for循环来遍历它,并且不需要关心 StopIteration 异常。

b = (x for x in range(10))

for x in b:

print(x)

# 0

# 1

# 2

# 3

#...

1|2函数中使用yield创建生成器的方法

如果如果生成器推算的算法比较复杂,用类似列表生成式的 for 循环无法实现的时候,还可以用函数来实现。把你要返回的值前面加yield 即可。

使用函数实现上面代码:

def fn():

for x in range(3):

yield x

# 遍历函数实现的生成器

f = fn()

print(next(f))

# 0

print(next(f))

# 1

print(next(f))

# 2

print(next(f))

# Traceback (most recent call last):

# File "", line 1, in

# StopIteration

使用生成器实现斐波拉契数列:

def fib(count):

n = 0

a,b = 0,1

while n < count:

yield b

a,b = b,a+b

n += 1

return "done"

f = fib(5)

print(next(f))

# 1

print(next(f))

# 1

print(next(f))

# 2

print(next(f))

# 3

print(next(f))

# 5

print(next(f))

# Traceback (most recent call last):

# File "", line 1, in

# StopIteration: done

yield执行流程

当执行next(f)时,函数开始执行到yield,yield 右边的变量x作为next()的返回值被返回,此时函数保存当前的运行状态,并暂停执行。

再次调用next(f)时,函数从上次暂停的位置开始继续执行,再次遇到yield时重复上面的操作

直到生成器遍历结束

我们在循环过程中不断调用 yield ,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。同样的,把函数改成generator后,我们基本上从来不会用 next() 来获取下一个返回值,而是直接使用 for 循环来迭代:

for x in fib(5):

print(x)

# 1

# 1

# 2

# 3

# 5

但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:

f = fib(5)

while True:

try:

print(next(f))

except StopIteration as e:

print("生成器返回值:%s"%e.value)

break

# 1

# 1

# 2

# 3

# 5

# 生成器返回值:done

1|3send方法

def gen():

i = 0

while i<3:

temp = yield i

print(temp)

i+=1

g = gen()

print(g.__next__())

# 0

print(g.send(None))

# None

# 1

print(next(g))

# None

# 2

print(g.send("哈哈")

# 哈哈

# Traceback (most recent call last):

# File "", line 1, in

# StopIteration

上面代码可以看出next()、next ()、send(None)是等价的并没有什么区别。

send()其实是比他们更高级的,在之前的代码中yield i是没有返回值的即输出为None。

如果修改send()的形参,那么yield i 的返回值就是括号中的形参,在上面的代码中g.send("哈哈")相当于temp = "哈哈",并且g.send("哈哈")的返回值就是变量i。

使用send时要注意,第一次调用生成器对象时,send()不能传参数否则会报错,第一次必须是send(None),或者第一次调

用next()、next ()也可以。

3|0闭包

3|1什么是闭包

在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包

def test(number):

def test_in(number_in):

print("test_in函数 的number_in=%s"%number_in)

return number_in+number

# 返回test_in函数的引用

return test_in

ret = test(20)

print(ret(100)) # 相当于直接调用test_in函数,并给它传值100

# test_in函数 的number_in=100

# 120

print(ret(200))

# test_in函数 的number_in=200

# 220

3|2闭包的一个例子

在数学中,一次函数:y=kx+b,在一条确定的直线中,它的k、b是不变的。求y时,根据确定的k、b、x来求出。

def line_conf(k, b):

def line(x):

return k*x + b

return line

line1 = line_conf(1, 1)

line2 = line_conf(4, 5)

print(line1(5))

print(line2(5))

# 6

# 25

如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。

4|0装饰器

4|1什么是装饰器

装饰器就是对一个函数进行装饰,给这个函数增加额外的功能。

def logging(func):

def wrap():

print("正在打印日志!")

func()

return wrap

@logging # 该装饰器为函数增加了打印日志的额外功能,并且之前函数内部代码不会改变。

def login():

print("张三正在登陆。")

login()

# 正在打印日志!

# 张三正在登陆。

4|2两个装饰器

def makeBold(fn1):

def wrapped():

print("----1----")

return ""+fn1()+""

return wrapped

def makeItalic(fn2):

def wrapped():

print("----2----")

return ""+fn2()+""

return wrapped

@makeBold

@makeItalic

def f1():

print("----3----")

return "hello world"

ret = f1() # 此时f1并不是f1函数,它是makeBold装饰器返回的wrapped函数的引用。

print(ret)

"""

输出结果:

----1----

----2----

----3----

hello world

"""

调用流程:

把函数f1的引用传入装饰器makeItalic中的变量fn2,此时fn2指向f1函数。

把装饰器makeItalic中wrapped函数的引用传入装饰器makeBold的变量fn1,此时fn1指向装饰器makeItalic中的wrapped函数。

ret = f1()表是执行f1所指向的函数,并返回给ret。

4|3装饰器带参数

一般情况下装饰器内部函数的参数都是不定长参数,保证通用性,确保装饰任何函数时都不会出错。

def logging(func):

def wrap(*args,**kwargs):

print("正在打印日志!")

func(*args,**kwargs)

return wrap

@logging # 该装饰器为函数增加了打印日志的额外功能,并且之前函数内部代码不会改变。

def login(name,dic):

print("%s正在登陆。"%name)

print(dic)

login("李四",{"sex":"男"})

# 正在打印日志!

# 李四正在登陆。

# {'sex': '男'}

4|4类装饰器

class Test(object):

def __init__(self, func):

print("---初始化---")

print("func name is %s"%func.__name__)

self.__func = func

def __call__(self):

print("---装饰器中的功能---")

self.__func()

@Test

def test():

print("----test---")

test()

"""

输出结果:

---初始化---

func name is test

---装饰器中的功能---

----test---

"""

说明:

当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象并且会把test这个函数名当做参数传递到__init__方法中即在__init__方法中的func变量指向了test函数体。

test函数相当于指向了用Test创建出来的实例对象。

当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法。

为了能够在__call__方法中调用原来test指向的函数体,所以在__init __方法中就需要一个实例属性来保存这个函数体的引用所以才有了self.__func = func这句代码,从而在调用__call __方法中能够调用到test之前的函数体。

总结

以上所述是小编给大家介绍的python中的生成器、迭代器、闭包、装饰器,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

本文标题: 详解python中的生成器、迭代器、闭包、装饰器

本文地址: http://www.cppcns.com/jiaoben/python/269525.html

python的装饰器迭代器与生成器_详解python中的生成器、迭代器、闭包、装饰器相关推荐

  1. python3 yield 大文件_详解Python3中yield生成器的用法

    任何使用yield的函数都称之为生成器,如: def count(n): while n > 0: yield n #生成值:n n -= 1 另外一种说法:生成器就是一个返回迭代器的函数,与普 ...

  2. python比较两个字符串相似度_详解Python 字符串相似性的几种度量方法

    字符串的相似性比较应用场合很多,像拼写纠错.文本去重.上下文相似性等. 评价字符串相似度最常见的办法就是:把一个字符串通过插入.删除或替换这样的编辑操作,变成另外一个字符串,所需要的最少编辑次数,这种 ...

  3. python文件对象是可以迭代的_详解python可迭代对象、迭代器和生成器

    可迭代对象 什么是可迭代对象?顾名思义就是可以迭代的一个对象,再通俗点就是可以被for循环遍历的对象,如常用的list.str等数据类型.我们可以使用isinstance来判断这个数据是否是可迭代对象 ...

  4. python爬取网易云歌单_详解python selenium 爬取网易云音乐歌单名

    目标网站: 首先获取第一页的数据,这里关键要切换到iframe里 打印一下 获取剩下的页数,这里在点击下一页之前需要设置一个延迟,不然会报错. 结果: 一共37页,爬取完毕后关闭浏览器 完整代码: u ...

  5. python for和while的用法区别_详解python while 函数及while和for的区别

    1.while循环(只有在条件表达式成立的时候才会进入while循环) while 条件表达式: pass while 条件表达式: pass else: pass 不知道循环次数,但确定循环条件的时 ...

  6. python类的静态属性和静态方法_详解Python中的静态方法与类成员方法

    前言 因为Python的水平目前一直是处于能用阶段,平时写的脚本使用的Python的写法也比较的简单,没有写过稍微大一点的项目.对Python中的类,类之间的组织关系,整个项目中类之间如何耦合还缺乏认 ...

  7. python最早引入json的版本_详解Python在使用JSON时需要注意的编码问题

    写这篇文章的缘由是我使用 reqeusts 库请求接口的时候, 直接使用请求参数里的 json 字段发送数据, 但是服务器无法识别我发送的数据, 排查了好久才知道 requests 内部是使用 jso ...

  8. 用python把图片换成蓝底_详解Python给照片换底色(蓝底换红底)

    现在网上出现了很多在线换底色的网页版工具是这么做的呢?其实用Python就可以实现. 环境要求 Python3 numpy函数库 opencv库 安装 下载适应版本的numpy函数库,我电脑是WIN1 ...

  9. python黑屏改成白底_详解Python给照片换底色(蓝底换红底)

    现在网上出现了很多在线换底色的网页版工具是这么做的呢?其实用Python就可以实现. 环境要求 Python3 numpy函数库 opencv库 安装 下载适应版本的numpy函数库,我电脑是WIN1 ...

最新文章

  1. 信息系统项目管理师笔记(信息系统篇)第一讲
  2. Python面试题40问
  3. Scala学习(二)--- 控制结构和函数
  4. 高端企业级存储IBM XIV访谈视频
  5. 重载(overload)与重写(override)的区别
  6. 万网绑定二级域名_Hexo+yilia主题网站绑定个性域名
  7. Win11系统如何设置黑暗模式
  8. java 淘口令_淘口令解析
  9. gitlab取消邮箱验证(适用gitlab各个版本)
  10. 红米k20适配android q,比谷歌还快,红米K20 PRO首发安卓Q稳定版,只有华为心里苦...
  11. 单片机的俄罗斯方块游戏设计
  12. 解决W5500,DHCP获取IP地址失败的问题,移植官方例程需要特别注意!!!
  13. MBR“主引导记录”的局限性与GPT GUID分区表的优势
  14. 参加最牛逼的运营人年终聚会,是种什么样的体验
  15. python分数约分_Python基础知识
  16. 计算机里的word怎么重装,word能卸载重装吗 word卸载重装
  17. ibatis中resultMap和resultClass的区别 以及parameterClass 的取值
  18. 服务器系统需要安装什么软件有哪些,在服务器上安装操作系统和必备软件
  19. 示波器仪器设备自动化校准计量检测软件系统NSAT-3010
  20. Java基础面试题/知识点总结

热门文章

  1. Lua 中写 C 扩展库时用到的一些技巧
  2. Linux进程间通信——使用命名管道
  3. 从头学习Drupal--基本架构三
  4. 1122. 数组的相对排序
  5. 山西台达plc可编程控制器_(PLC)可编程控制器的编程语言你了解吗?不妨看看...
  6. mysql id用什么类型_mysql 证明为什么用limit时,offset很大会影响性能
  7. 数据结构与算法之-----栈的应用(三)
  8. python如何连接sql server数据库_Python连接SQLServer数据库
  9. 校招真题练习001 牛牛找工作(网易)
  10. windows10风格 springboot mybatis 项目框架源码 shiro 集成代码生成器