欢迎光临散文网 会员登陆 & 注册

Python迭代器、生成器与装饰器(笔记补充)

2023-07-19 19:15 作者:水母山楂  | 我要投稿

〇、前言

笔记补充系列补全原视频笔记没有出现的Python知识,所以内容非常依赖参考内容,专栏有错误的地方欢迎指出

WPS笔记及其他内容百度网盘链接:

https://pan.baidu.com/s/1fTwjyoM81_OOAccPNhGE9Q?pwd=h3fg

参考网址在下面列出:

https://docs.python.org/zh-cn/3.11/reference/expressions.html?

https://www.runoob.com/python3/python3-iterator-generator.html

https://www.runoob.com/w3cnote/python-func-decorators.htm

(1)、迭代器

1. 概念

迭代是访问集合元素的一种方式,迭代器是一个可以记住遍历的位置的对象

2. 过程

迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退

3. 可被创建迭代器对象

字符串、列表、元组等可迭代对象

4. 基本方法

4.1. iter()

生成迭代器对象

iter(object[, sentinel)

object——可迭代对象

sentinel——如果该参数被传递,则参数object必须是一个可调用对象,此时,iter创建了一个迭代器对象,每次调用该对象__next__()方法时,都会调用object(不带参数),直到返回值等于sentinel,这时调用__next__()方法会引发StopIteration

补充:内置函数callable()

检查一个对象是否是可调用的。如果返回True,对象仍然可能调用失败;但如果返回False,调用对象object绝对不会成功

# 例如上面iter()自动调用object,如果需要参数,会调用失败

callable(object)

object——对象

大概有以下7类可调用对象:  # 可调用对象可用"对象名()"进行调用

1.用户自定义的函数

2.内置函数

3.内置方法

4.类方法

5.类

6.类定义__call__方法的类的实例

7.生成器函数

4.2. next()

返回迭代器的下一项

next(iterable[, default])

iterable——迭代器对象

default——可选,用于设置在没有下一个元素时返回该默认值,不设置且没有下一个元素时触发StopIteration异常

4.3. for语句

迭代器对象可以使用常规for语句进行遍历

示例:

运行结果:

True True

1

2

3

stop

[随机数量的2 + None]

5. 创建一个迭代器

把一个类作为一个迭代器使用需要在类中实现两个方法

5.1. __iter__()方法

返回一个特殊的迭代器对象,这个迭代器对象实现了__next__()方法并通过StopIteration标识迭代的完成

5.2. __next__()方法

返回迭代器对象的下一项

示例:

运行结果:

3 6 12 24 48 96 192 384

6. StopIteration异常

用于标识迭代的完成,防止出现无限循环的情况,在__next__()方法中可设置完成指定循环次数后触发该异常来结束迭代(raise语句)

示例:

运行结果:

3 6 12 24 48 96 192 384 768 1536 stop

(2)、生成器

1. 概念

在迭代的同时生成元素,本质上也是迭代器,能节省内存

2. 创建

2.1. 使用生成式

(表达式 for 自定义变量 in 可迭代对象)

2.2. 使用生成器函数

3. 生成器函数

3.1. 定义

函数内使用了yield语句的函数

3.2. 作用

调用函数时,不会执行函数中的代码,返回值是一个生成器(对象)

4. 调用

使用for循环或next(),与迭代器相同

5. 生成器函数创建的生成器被调用时

执行生成器函数中的代码,每次遇到yield语句时会暂停并保存当前所有的运行信息,返回yield的值,并在下一次被调用时从当前位置继续执行(yield语句下一行)

6. yield语句

yield 值[, 值]  # 后面加多个数值,返回的值是元组类型

示例:

运行结果:

<class 'generator'>

2 4 6 8 10 12 14 16 18 20 stop

<class 'generator'>

3 6 12 24 48 96 192 384 768 1536

7. 生成器对象的方法

7.1. __next__()

相当于next(生成器对象)或使用for循环,这会启动生成器,或是从上次执行到yield语句的位置恢复执行,返回下一次执行到yield语句的值

7.2. send(value)

恢复执行生成器,并在上次执行到yield语句此返回值value,也会返回下一次执行到yield语句的值

# 如果想用send()启动生成器,则必须先传入None,因为此时函数没有接收值value的yield语句

7.3. throw(value)/throw(type[, value[, traceback]])

在生成器暂停处引发异常,并返回下一个值(如果生成器没有生成则引发StopIteration异常)

# 生成器没有捕获该异常或是引发另一个异常则将异常传递给调用处

7.4. close()

在生成器暂停处引发GeneratorExit

如果生成器函数正常退出、关闭或引发GeneratorExit(由于未捕获该异常)则关闭并停止阻塞调用处

如果生成器产生一个值,则关闭并引发RuntimeError

如果生成器引发其他异常,则将异常传递给调用处

如果生成器已经由于异常关闭或正常退出则close()不会任何事

# GeneratorExit继承自BaseException而不是Exception

# 如果生成器在被销毁前没有恢复执行,则将调用它的close()方法

示例:

运行结果:

a

b

ValueError异常被捕获

生成器已关闭


8. yield from语句

8.1. 概念

委托给子迭代器

8.2. 语法

yield from <expr>

<expr>必须是一个可迭代对象(可以是列表、元组、迭代器、生成器等)

8.3. 作用

当执行到该语句时,生成器会迭代该可迭代对象<expr>,并将迭代的值传递给调用处(一次调用传递一个值)。send()和throw()方法传入的值或异常会传递给该对象的相应方法,如果没有则send()引发AttributeError或TypeError,而throw()引发传入的异常

当下层迭代器完成时,被引发的StopIteration实例的value属性会作为该语句的返回值

补充:在生成器中,使用return语句会结束迭代,并且return返回的值会作为引发StopIteration实例的value属性的值

示例:

运行结果:

n的值为: 下层迭代结束

n的值为: 下层迭代结束

--------

[1, 2, 3, 101, 102, 103, 201, 202, 203]


(3)、装饰器(decorator/wrapper)

1. 函数对象

Python中一切皆对象,函数是一个对象,可以赋值给变量

示例:

运行结果:

1

------

1

<function a at [内存地址]>

2. 从函数中返回函数

函数对象可以作为函数的返回值

示例:

运行结果:

<function a at [内存地址]> 1

3. 将函数作为参数传给另一个函数

函数对象也可以作为函数的参数

示例:

运行结果:

1

4. 函数装饰器

4.1. 概念

返回值是另一个函数(可调用对象)的函数,该函数在不修改被装饰对象(函数)源代码和调用方式的前提下为被装饰对象(函数)添加新功能

4.2. 使用

补充:闭包

闭包是能读取其他函数内部变量的函数。语法通常是在函数A内创建函数B,并且函数A返回了函数B,函数B就是闭包,函数A的变量和参数叫自由变量

4.2.1. 简单装饰器

示例:

运行结果:

6 <function plus_1.<locals>.wrapper at [内存地址]>

# 函数five原来作用是输出五,使用deco修饰后有了输出值加一的功能

过程分析:

1.定义plus_1装饰器函数,参数是函数对象func,返回值是嵌套在里面的wrapper函数

2.将five函数进行装饰,调用plus_1函数并将five函数对象传参,将返回值wrapper函数对象赋值给five函数对象

3.这时five的内存地址指向wrapper,调用five就相当于调用wrapper函数,wrapper里面的func就是还未被修饰的five函数(原始函数five)

4.2.2. 语法糖写法

补充:语法糖

语法糖指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用,通常也能够增加程序的可读性,从而减少程序代码出错的机会

使用"@装饰器名"对函数进行装饰,放在函数开始定义的地方

示例:

运行结果:

6 <function plus_1.<locals>.wrapper at [内存地址]>

4.3. 多个装饰器

一个函数可以同时被多个装饰器装饰,装饰器的执行顺序是从里到外、

示例:

运行结果:

11  # 先执行乘2,再加1

4.4. 被装饰函数的参数

当被装饰函数需要参数时,可以在定义wrapper()函数时指定参数*args, **kwargs,再在wrapper()函数中调用原始函数时将参数传递进去。使用*args, **kwargs的目的是确保任何参数都能适用

示例:

运行结果:

9  # (3+5)+1

4.5. 带参数的装饰器

4.5.1. 概念

在调用装饰器时提供其他参数,可根据不同参数实现不同的装饰功能

4.5.2. 使用

将原有装饰器再进行一次嵌套,嵌套的函数带参数并返回原有装饰器

# 可以理解为一个含有参数的闭包

调用时"@装饰器名(参数[, ...])"  # 这里装饰器名是装饰器最外层的函数名

示例:

运行结果:

3 12

4.6. 保留被装饰函数的属性

函数被装饰后,原函数名的元信息变成了装饰器函数的信息,如果需要保留原函数的元信息(也就是将原函数的元信息,拷贝到相应的装饰器函数里),就可以使用内置的装饰器@functools.wraps

# 元信息是例如__name__、__doc__等属性

# functools是Python内置模块,使用前需要载入

在装饰器wrapper函数前用"@functools.wraps(func)"装饰

# func是传入装饰器的函数对象


示例:

运行结果:

c d

wrapper_a d

5. 类装饰器

5.1. 概念

类也可以作为装饰器,类装饰器的返回值是一个类的实例对象。相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点

5.2. 使用

由于装饰器的返回值是一个可调用对象,所以必须在类里面实现__call__()方法。__call__()方法在你每调用一个类的实例时会被执行一次

示例1:

运行结果:

[运行时间]

1000000

示例2:

运行结果:

# 三秒过后

[运行时间]

1000000 wrapper










Python迭代器、生成器与装饰器(笔记补充)的评论 (共 条)

分享到微博请遵守国家法律