第十三章 迭代器、生成器、 装饰器

2024-05-12 11:32

本文主要是介绍第十三章 迭代器、生成器、 装饰器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、可迭代对象

1. 容器类(能存放多个元素的数据类型):

    ① 序列:字符串、列表、元组、字节

    ② 字典

    ③ 集合

    # 组件:开发社区写的一堆类

    

2. 迭代对象iteration

    --- 可进行遍历的对象

    > 可迭代对象都是Iterable的扩展类(子类、衍生类,派生类)

    > 重写了__iter__(self),可以返回一个【迭代器】

        ---  3.X所有可迭代对象都实现了__iter__(self),之前有的实现__getitem__

验证法:

    from collections.abc import Iterableprint(issubclass(dict, Iterable))

    

3. 迭代器iterator

    迭代器是迭代对象的特殊形式,即是迭代对象Iterable的子类

    迭代对象无法遍历,迭代器下有next方法才能遍历,因此调用迭代对象下的迭代器才能遍历

    

    迭代对象:不需要显式继承Iterable,只需要实现__iter__方法,返回迭代器

    迭代器: 不需要显式继承Iterable,只需要实现__iter__方法和__next__方法,返回迭代器

        (iter方法:    返回迭代器

        next方法:获得单个元素)

    > 如果通过next遍历元素,如果迭代器为空,返回StopIteration错误

    > 迭代器是一次性的,被next遍历后元素消失

    > for循环底层,每次都从迭代对象中,重新初始化一个迭代器

    eg:

    li = [1,2,4]

    # 获取迭代器

    ①   li.__iter__()       # 魔法方法不支持显示调用

    ② li.iter

    # 获得单个元素

    ①   li.__nex__t()

    ②   li.next

    print(next(li))

li = [1,2,4]
# 获取迭代器
①	li.__iter__()		# 魔法方法不支持显示调用
②  li.iter
# 获得单个元素
①	li.__nex__t()
②	li.next
print(next(li))
eg.# 模仿for循环底层while True:it = iter(li)while True:try:item = next(it)except StopIteration:del itbreak

 

4. 自定义迭代类型

    满足抽象基础规范、

    迭代对象: 实现iter方法,返回迭代器

    迭代器 : next, iter方法返回自己

class My_Iterable:def __iter__(self):self.liter = [1,2,3,4]return li.__iter__()return My_Iteror(self.liter)
class My_Iteror:def __init__(self, li):self.liter = liself.index = 0def __iter__(self):return selfdef __next__(self):if self.index < len(self.liter)self.liter[self.index]self.index += 1return relse:raise StopIteration
m = My_Iterable()
it = iter(m)
print(next(it))# 验证
print(isinstance(m, Iterable))
print(issubclass(My_Iterable, Iterable))

 

    迭代器 :只能用一次

    迭代对象:用来产生迭代器,可以狗仔复杂数据类型,提供给迭代器使用

    

5. 迭代器缺点:

    (1) 实现一个迭代器,需要iter,next方法

    (2) 不使用for循环,需要自己去捕获StopIteration异常

    (3) 一次性数据全部迭代,结果不一定全部使用,占用内存

 

二、 生成器

    --- 2.5后出现的可迭代对象,即底层使用了迭代器实现

1. 定义:

    懒加载(按需加载)的迭代器

2. 生成器的特征

    生成器不会一次性计算出存储的数据,而是一次只计算一个数据

3. 生成器的实现:

    > 生成器的数据获得方式:

        ① next

        ② 遍历

        

3.1 生成器表达式

    元组生成式 = 生成器

    x = (i**2 for in range(5))

    print(next(x))

3.2 生成器函数

    --- 带有yield关键字的函数

    yield: 能够让程序暂停到yeild位置,产出值

            注意:生成器函数调用时,不是直接执行,而是创建生成器对象,

    >   生成器可能包含多个yield

    >   生成器底层是迭代器

    >   可以通过next方法获得内部远胜于,也可以通过for遍历

    >   当函数终止时,再次获取元素,报StopIteration异常

    >   函数执行遇到yiled,程序暂停在该位置,返回对应值,将控制前交给调用者

def f():print('函数开始')for i in range(1, 101):print('yield前;')yield i		# 暂停,产出返回值iprint('yield后:',i)return i
g = f()
next(g)
next(g)

3.3 yield表达式

    生成器:

        校核值 = yield 产出值

    调用端:

        产出值 = send(校核值)

    

    第一次调用生成器:产生生成器对象

    next:激活生成器

    

    > 生成器表达式的结果 是 调用生成器send方法传入的参数

    > 对象.send(None) == next(对象)

    > 激活生成器:① next()

                 ② send(None),必须是None

    > 获取生成器元素

        next(g)

        g.send('随意')

       

 def gen():for i in range(100):value = yield i**2      # value是send函数传入值,i**2为产出值,两者不会赋值,互不相干# value是send传入的参数,i是send或者next返回值print(f'value={value}')g = gen()               # 创建对象print(next(g))          # 激活生成器,传出0print(g.send('玩一玩'))    # value = '玩一玩,返回值为i

    

pl.需求,产生1 2 3 4 5,提示,输出5 4 3 2 1,....

   

pl.需求,产生1 2 3 4 5,提示,输出5 4 3 2 1,....
# 编写生成器,调整生成方案
import time
def gen():msg = ''while True:x = yield msgif x == 5:mag = 'too big'elif x == 1:msg = 'too small'
g = gen()# 在主线插入生成器调用
while True:time.sleep(0.5)print(x)msg = g.send(x)if msg = 'too big':x -= 1else msg == 'too small'x += 1

        

三、 装饰器

> 装饰器的作用:

    (1) 扩展函数

    (2) AOP(面向切面):将共用模块提取出来,形参一个单独组件

 

1. 闭包

    --- 在内部函数中访问外部函数的变量;

        在外部函数中返回内部函数的函数名(调用)

    (1) 条件:

        ① 嵌套函数

        ② 内部函数能够访问外围变量

        ③ 外部函数return 内部函数名

    eg.

    def outer():

        x = 1

        sef inner():

            print(x)

        return inner

    a = outer()

    print(a.__closure__)

 

    (2) 适用情形

        ① 函数中有一些变量在被调用后仍然希望保留’

        ② 函数需要扩展功能,但是不能修改原函数的名字

	# 原始
from datetime import datetime
def on_duty(name):print(f'{name}在上班')
def off_duty(name):print(f'{name}离开了')print(datetime.now())# 闭包,不修改原始功能,添加新功能
def new(func):def inner(name):func(name)print('添加性能')return inner
on_duty = new(on_duty)
on_duty('Geoffrey')

2. 装饰器的作用:  

    > 用来处理被装饰的函数,返回函数的新名字,采用了闭包的思想

    > 在不修改原函数的基础上,对现有函数进行扩充、功能扩展

    

    (1) 格式

        在被调用函数上面加 @装饰名

            --- 一种语法糖

        原函数名 = 装饰函数(被装饰函数)

def new(func):def inner(name):func(name)print('添加性能')return inner@new
def on_duty(name):print(f'{name}在上班')

3. 装饰器的优化

    (1) 参数的优化 --- 万能参数

    (2) 返回值的优化

        ---- 在inner中,提取func返回值作为inner返回值

    (3) 装饰器的叠加

        --- 使用装饰器扩展更多的功能,

from functools import wrapsdef record(*args):def _inner(func):@wraps(func)                    # 保留原函数的元信息def __inner(*arg, **kwarg):     # 万能参数r = func(*arg, **kwarg)print(f'{args[0]}天后去{args[1]}向领导汇报工作')return rreturn __innerreturn _inner# 测试嵌套装饰器
def new(func):                          # 为原函数添加的新功能def inner(*args, **kwargs):r = func(*args, **kwargs)       # 添加返回值print('new装饰器添加性能')return r                        # 此处对应原函数返回值return inner@record(20, '上海')
@new
def on_duty(name):print(f'{name}在上班')on_duty('Geoffrey')

4. 含有参数的装饰器

        --- 如果装饰器中需要使用其他参数,在外部做一个闭包

            在装饰原函数的时候,在装饰器后面加上(参数)

            不要在装饰器层传入参数,装饰器层只传入函数名    

 

5.  保留元信息 (函数注释)

    functools 下的 wraps实现元信息的保留

    在inner层上面添加:

        @wraps(func) --- 形式参数func

        

6. 类装饰器

    --- 实现装饰器,除了装饰器函数,还可以使用类方法

   

class New:def __init__(self, func):self.func = func#使对象能通过方法调用,即执行 对象()def __call__(self, *args, **kwargs):self.func(*args, **kwargs)print('随便添加其他函数')@new
def play(a, b):from datetime import datetimeprint(datetime.now())

 

这篇关于第十三章 迭代器、生成器、 装饰器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/982502

相关文章

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

Python中的属性装饰器:解锁更优雅的编程之道

引言 在Python的世界里,装饰器是一个强大的工具,它允许我们以一种非侵入性的方式修改函数或方法的行为。而当我们谈论“属性装饰器”时,则是在探讨如何使用装饰器来增强类中属性的功能。这不仅让我们的代码更加简洁、易读,同时也提供了强大的功能扩展能力。本文将带你深入了解属性装饰器的核心概念,并通过一系列实例展示其在不同场景下的应用,从基础到进阶,再到实际项目的实战经验分享,帮助你解锁Python编程

多线程篇(阻塞队列- LinkedBlockingDeque)(持续更新迭代)

目录 一、LinkedBlockingDeque是什么 二、核心属性详解 三、核心方法详解 addFirst(E e) offerFirst(E e) putFirst(E e) removeFirst() pollFirst() takeFirst() 其他 四、总结 一、LinkedBlockingDeque是什么 首先queue是一种数据结构,一个集合中

多线程篇(阻塞队列- LinkedBlockingQueue)(持续更新迭代)

目录 一、基本概要 1. 构造函数 2. 内部成员 二、非阻塞式添加元素:add、offer方法原理 offer的实现 enqueue入队操作 signalNotEmpty唤醒 删除线程(如消费者线程) 为什么要判断if (c == 0)时才去唤醒消费线程呢? 三、阻塞式添加元素:put 方法原理 图解:put线程的阻塞过程 四、非阻塞式移除:poll方法原理 dequ

纸牌函数生成器

此模板用来生成纸牌类的测试数据,本人手打,不合理或缀余的地方希望大神指出。 T=10000(测试数据组数), t (两摞相等的牌,每摞牌的数量); 每张牌用A,2~9,T,J,Q,K;表示牌面大小; 用S,H,C,D;表示花色。 共52张牌。 #include<stdio.h>#include<time.h>#include<stdlib.h>#include<string.

六、我们应当怎样做需求调研:迭代

前面我一直在反复强调这样一个观点,需求分析不是一蹴而就的,是一个反复迭代的过程。它将从第一次需求分析开始,一直持续到整个项目生命周期。为什么这样说呢?让我们一起来分析分析。  在第一次的需求分析阶段,我们在一段时期内需要与客户进行反复地讨论,这个过程往往是这样一个反复循环的过程:需求捕获->需求整理->需求验证->再需求捕获••••••  需求捕获,就是我们与客户在一起开研讨会

【生日视频制作】酒吧一群美女车展模特大屏幕视频改字AE模板修改文字软件生成器教程特效素材【AE模板】

生日视频制作教程酒吧一群美女车展模特大屏幕视频改字AE模板修改文字特效广软件告生成神器素材祝福玩法AE模板工程 怎么如何做的【生日视频制作】酒吧一群美女车展模特大屏幕视频改字AE模板修改文字软件生成器教程特效素材【AE模板】 生日视频制作步骤: 安装AE软件 下载AE模板 把AE模板导入AE软件 修改图片或文字 渲染出视频

WPF入门到跪下 第十三章 3D绘图 - 3D绘图基础

3D绘图基础 四大要点 WPF中的3D绘图涉及4个要点: 视口,用来驻留3D内容3D对象照亮部分或整个3D场景的光源摄像机,提供在3D场景中进行观察的视点 一、视口 要展示3D内容,首先需要一个容器来装载3D内容。在WPF中,这个容器就是Viewport3D(3D视口),它继承自FrameworkElement,因此可以像其他元素那样在XAML中使用。 Viewport3D与其他元素相

[Python]生成器和yield关键字

生成器和yield关键字 1.生成器介绍: 概述: ​ 它指的是 generator, 类似于以前学过的: 列表推导式, 集合推导式, 字典推导式… 作用: ​ 降低资源消耗, 快速(批量)生成数据. 实现方式: ​ 1.推导式写法. my_generator = (i for i in range(5)) ​ 2.yield写法. def get_generator():for i