【python高级用法】迭代器、生成器、装饰器、闭包

迭代器

  • 可迭代对象:可以使用for循环来遍历的,可以使用isinstance()来测试。

  • 迭代器:同时实现了__iter__()方法和__next__()方法,可以使用isinstance()方法来测试是否是迭代器对象


from collections.abc import Iterable, Iterator
li = [11, 22, 33, 44, 55]

print(isinstance(li, Iterable)
iterator_li = iter(li)
print(isinstance(iterator_li, Iterator)

使用类实现迭代器

两个类实现一个迭代器


class MyList(object):
    """自定义的一个可迭代对象"""
    def __init__(self):
        self.items = []

    def add(self, val):
        self.items.append(val)

    def __iter__(self):
        #python中万物皆对象,将该类对象的引用self作为实参传入到MyIterator类中
        myiterator = MyIterator(self)
        return myiterator


class MyIterator(object):
    """自定义的供上面可迭代对象使用的一个迭代器"""
    #这里的mylist就MyList对象
    def __init__(self, mylist):
        self.mylist = mylist
        # current用来记录当前访问到的位置
        #每一次调用for循环时,索引位置都从零开始
        self.current = 0

    def __next__(self):
        if self.current < len(self.mylist.items):
            item = self.mylist.items[self.current]
            self.current += 1
            return item
        else:
            raise StopIteration

    def __iter__(self):
        return self

一个类实现迭代器


class MyList(object):
    """自定义的一个可迭代对象"""
    def __init__(self):
        self.items = []
        self.current = 0

    def add(self, val):
        self.items.append(val)

    def __iter__(self):
        #返回自身引用,自己本身就是一个迭代器对象
        return self

    def __next__(self):
        if self.current < len(self.items):
            item = self.items[self.current]
            self.current += 1
            return item
        else:
            #使用for循环第二次遍历时,self.current可以从0开始
            self.current = 0
            raise StopIteration
  • 可迭代对象与迭代器的总结

  1. 一个具备了__iter__方法的对象,就是一个可迭代对象

  1. 当对一个可迭代对象调用iter()函数时,它会自动调用这个可迭代对象的__iter__方法,这个方法返回的对象当作迭代器

  1. 当对一个迭代器对象调用next()函数时,他会自动调用这个迭代器对象的__next__方法,这个方法返回想要的数据

  1. 迭代器一定是可迭代对象,可迭代对象不一定是迭代器

  1. 数据类型list、dict、str等是Iterable单不是Iterator,不过可以通过iter()函数获得一个Iterator对象

  • 迭代器的应用

  1. 如果每次返回的数据值不是在一个已有的数据集合中,而是通过程序按照一定的规律计算生成的,那就不用再依赖一个已有的数据集合,也就是说不用再将所有要迭代的数据都一次性缓存下来,这样可以节省大量的存储(内存)空间。


class FeiboIterator(object):
    """斐波那契数列迭代器"""
 
    def __init__(self, n):
        # 斐波那数列值的个数
        self.n = n
        # 记录当前遍历的下标
        self.index = 0
        # 斐波那数列前面的两个值
        self.num1 = 0
        self.num2 = 1
 
    def __next__(self):
        """被next()函数调用来获取下一个数"""
        if self.index < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1 + self.num2
            self.index += 1
            return num
        else:
            raise StopIteration
 
    def __iter__(self):
        """迭代器的__iter__返回自身即可"""
        return self
 
 
if __name__ == '__main__':
    fb = FeiboIterator(20)
    for num in fb:
        print(num, end=' ')

生成器

生成器的定义

  1. 使用了yield关键字的函数不再是函数,而是生成器。

  1. yield关键字有两点作用:

  • 保存当前运行状态(断点),然后暂停执行,即将生成器(函数)挂起

  • 将yield关键字后面表达式的值作为返回值返回,此时可以理解为起到了return作用

  1. 可以使用next()函数让生成器从断点处继续执行,唤醒生成器(函数)

  1. python3中的生成器可以使用return返回最终运行的返回值

  1. 生成器是这样一个函数,他记住上一次返回在函数体中的位置。对生成器函数的第二次(或第n次)调用跳转至函数中间,而上次调用的所有的局部变量都保持不变。生成器不仅记住了他的数据状态,生成器还记住了它在流程控制构造(在命令式编程中,这种构造不只是数据值)中的位置。

  1. 生成器的特点:

  • 存储的是生成数据的方式(即算法),而不是存储生成的数据,因此节约内存。

生成器的使用


def create_points():
    k = 2
    b = 1
    x = 0
    while True:
        y = k * x + b
        #当使用send方法时,会将send方法中的参数赋给temp,send()方法与next()方法类似,都可以取生成器中的下一个元素。
        temp = yield (x,y)
        if temp:
            k, b = temp
        x = y

if __name__ == '__main__':
    #不再是一个普通函数的调用,因为函数体内包含yield关键字,此时是生成一个生成器对象
    g = create_points()
    # print(next(g))
    # print(next(g))
    # print(g.send((3, 4)))
    # print(next(g))
    # print(next(g))
    count = 0
    for i in g:
        if count > 3:
            break
        print(i)
        count += 1

参考链接:

python生成器的原理和业务场景下的使用_for line in tqdm(f, desc='read sentence_cuts'):如果不-CSDN博客

装饰器

装饰器的定义

装饰器可以在不改变某函数结构和调用方式基础之上,为其增加新的功能,并且最大化复用新的功能。

装饰器的应用场景

为函数增加日志记录、登录校验、权限校验等,我们可以将这些功能写成一个装饰器,然后直接应用到相应需要改功能的函数中即可,可以保证对原代码和函数零侵入。

装饰器的本质是一个闭包函数

  • 装饰器函数
def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        execution_time = end_time - start_time
        print(f"{func.__name__} cost time: {execution_time:.4f} s")
        return result
    return wrapper
  • 构造执行函数
@timing_decorator
def demo():
    time.sleep(5)
    

执行demo函数时,会打印该函数执行时间为5s

参考文献:

python装饰器全解--包含实现原理及应用场景_装饰器实现原理-CSDN博客

闭包

什么是闭包

概念:一个函数可以引用作用域外的变量,同时也可以在函数内部进行使用的函数,称之为闭包函数。而这个作用域外的变量,称之为自由变量。这个自由变量不同于C++的static修饰的静态变量,也不同于全局变量,它是和闭包函数进行绑定的。

  1. 闭包函数是函数的嵌套,函数内还有函数,即外层函数嵌套一个内层函数

  1. 在外层函数定义局部变量,在内层函数通过nonlocal引用,并实现指定功能,比如计数

  1. 最后外层函数return内层函数

  1. 主要作用:可以变相实现私有变量的功能,即用内层函数访问外层函数内的变量,并让外层函数内的变量常驻内存

为什么要使用闭包

  1. 封装变量: 闭包允许你创建一个包含函数和其所在环境中变量的封闭空间。这样,你可以隐藏一些变量,使其不易被外部访问,起到一定的封装作用。

  2. 保持状态: 闭包函数可以保持其创建时的状态。这意味着你可以在函数外部改变闭包内部的变量,并且在多次调用闭包时保持这些变量的状态。

  3. 函数工厂: 闭包函数可以用作函数工厂,动态生成函数。这对于根据不同情况生成不同行为的场景很有用。

  4. 实现装饰器: 闭包函数常用于实现装饰器模式,通过在函数外层包装其他函数来增强其功能,而无需修改原始函数的代码。

  5. 实现私有变量和方法: 通过闭包,你可以模拟出类似于面向对象编程中的私有变量和方法,限制对内部实现的访问。

闭包的应用场景是什么

创建一个计数器,但又不想让外部直接访问计数变量

def create_counter():
    count = 0  # 这个变量在闭包内

    def counter():
        nonlocal count  # 使用 nonlocal 关键字声明 count 不是局部变量
        count += 1
        return count

    return counter

# 创建一个计数器
my_counter = create_counter()

# 使用计数器
print(my_counter())  # 输出 1
print(my_counter())  # 输出 2
print(my_counter())  # 输出 3

在这个例子中,create_counter 函数返回了一个内部定义的 counter 函数count 变量被封装在 counter 函数的闭包中,因此外部无法直接访问。每次调用 my_counter() 时,计数器会递增并返回当前计数值。

这样做的好处是,我们可以创建多个独立的计数器,它们各自维护自己的状态,而不会互相干扰。闭包在这里提供了一种轻量级的状态封装和隔离的机制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/281739.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Hadoop安装笔记1单机/伪分布式配置_Hadoop3.1.3——备赛笔记——2024全国职业院校技能大赛“大数据应用开发”赛项——任务2:离线数据处理

将下发的ds_db01.sql数据库文件放置mysql中 12、编写Scala代码&#xff0c;使用Spark将MySQL的ds_db01库中表user_info的全量数据抽取到Hive的ods库中表user_info。字段名称、类型不变&#xff0c;同时添加静态分区&#xff0c;分区字段为etl_date&#xff0c;类型为String&am…

人工智能的第一性原理

今天跟大家分享一篇 北师大 - 图像处理研究中心主任 郭平教授的一篇文章 通过“四个问题”&#xff0c; 解释了人工智能的第一性原理 提出了如何运用第一性原理思维 来解决人工智能缺乏基本常识的问题 并且他建议将最小作用量原理 作为人工智能的第一性原理 什么是第一…

排序算法讲解

1&#xff09;排序思想&#xff1a; 2&#xff09;排序代码&#xff1a; 3&#xff09;注意点&#xff1a; 4&#xff09;时间/空间复杂度和稳定性 下面的排序是以实现升序讲解的。 &#xff08;一&#xff09;直接插入排序 1&#xff09;排序思想&#xff1a; 把待排序的…

【c语言】飞机大战2

1.优化边界问题 之前视频中当使用drawAlpha函数时&#xff0c;是为了去除飞机后面变透明&#xff0c;当时当飞机到达边界的时候&#xff0c;会出现异常退出&#xff0c;这是因为drawAlpha函数不稳定&#xff0c;昨天试过制作掩码图&#xff0c;下载了一个ps,改的话&#xff0c…

centos7安装nginx并安装部署前端

目录&#xff1a; 一、安装nginx第一种方式&#xff08;外网&#xff09;第二种方式&#xff08;内网&#xff09; 二、配置前端项目三、Nginx相关命令 好久不用再次使用生疏&#xff0c;这次记录一下 一、安装nginx 第一种方式&#xff08;外网&#xff09; 1、下载nginx ng…

Jenkins基础教程

目录 第一章、快速了解Jenkins1.1&#xff09;Jenkins中一些概念介绍1.2&#xff09;Jenkins和maven用途上的区别1.3&#xff09;为什么使用Jenkins1.4&#xff09;学习过程中的疑问 第二章、安装Jenkins2.1&#xff09;安装之前的准备2.2&#xff09;Windows中Jenkins下载安装…

DrGraph原理示教 - OpenCV 4 功能 - 单通道图

通道 OpenCV的核心处理对象是Mat&#xff0c;大体是一个二维数组&#xff0c;加上了各种功能函数。 很多的图像处理&#xff0c;会在单通道或二值化的基础上进行&#xff0c;比如连通域、目标识别等。这里的通道就是channels。 不同的图像处理算法可能对通道数有特定的要求。例…

计算机组成原理复习6

总线结构与控制练习题 计算机系统为什么采用总线结构&#xff1f; 解析&#xff1a;在冯诺依曼计算机体系当中&#xff0c;把计算机基本组成分成了五大部分。运算器&#xff0c;控制器&#xff0c;存储器&#xff0c;输入设备和输出设备。我们可以把运算器和控制器制作在一个芯…

字符串与模拟法

加密英文 输入一个字符串可用getline(cin,数组名) 字典序 在字符串中寻找子字符串 分糖果 代码 猴子选大王 代码 如果n号猴子被选中&#xff0c;则使得n号的猴子变成false&#xff0c;未出局的猴子为true。 if(pn1) p1;这个是将超出的下标重新变回1号&#xff0c;使其重新循…

DNS域名查询过程

目录 DNS&#xff08;Domain Names System&#xff09; 域名转IP IP转域名 域名 域名查询流程 浏览器DNS缓存 操作系统缓存 本地host文件 完整流程 递归查询 迭代查询 DNS&#xff08;Domain Names System&#xff09; 域名系统&#xff0c;将域名和 IP 地址进行转…

模型 冰山理论

本系列文章 主要是 分享 思维模型&#xff0c;涉及各个领域&#xff0c;重在提升认知。冰山下面才是重点。 1 冰山理论的应用 1.1 冰山理论在生活中的常见应用 人际交往&#xff1a;在人际交往中&#xff0c;很多人只关注表面的行为和语言&#xff0c;而忽略了内在的情感和动…

免费的云服务器推荐~三丰云

对于许多初创企业和小型公司来说&#xff0c;寻找一个经济实惠且可靠的云服务提供商是至关重要的。在这方面&#xff0c;三丰云以其免费虚拟主机和云服务器吸引了大量用户。 1. 注册与界面 注册三丰云的账户过程简单明了&#xff0c;只需按照步骤填写必要信息即可。其界面设计…

Unity之地形的构建

PS&#xff1a;公司没活干&#xff0c;好无聊偷偷摸鱼学Unity&#xff0c;害怕自己学完之后忘记&#xff0c;写下这一篇博客 先来看一下效果图&#xff1a;有山有水有树有草地 创建一个新的Unity3D项目 这里要用到Unity官方的免费资源包&#xff08;现在好像已经下架了百度网盘…

Mybatis分页插件之PageHelper生效and失效原理解析

文章目录 前言整合PageHelperPageHelper生效原理PageHelper的分页参数和线程绑定核心拦截逻辑生成分页SQLdialect.afterAll() PageHelper失效原理分页失效案例分页失效原理总结 Mybatis拦截器系列文章&#xff1a;从零开始的 MyBatis 拦截器之旅&#xff1a;实战经验分享 构建自…

S32K312使用ITCM向FLASH代码区写入数据

使用C40_IP的系列方法向FLASH代码区写入数据时&#xff0c;程序会卡死在读取写操作的状态C40_Ip_MainInterfaceWriteStatus()这个方法中。本文主要介绍S32K312通过ITCM的方式&#xff0c;通过C40_IP的方法向FLASH代码区成功写入数据的方法和步骤。 首先&#xff0c;验证一下C4…

macos下php 5.6 7.0 7.4 8.0 8.3 8.4全版本PHP开发环境安装方法

在macos中如果使用brew 官方默认的core tap 只可以安装官方最新的稳定版PHP, 如果想要安装 php 5.6 或者 php 8.4版本的PHP就需要使用第三方的tap , 这里分享一个比较全面的brew tap shivammathur/php 这个tap里面包含了从php5.6到最新版php8.4的所有可用最新版本PHP, 而且是同…

python大于等于小于等于,python大于等于怎么写

大家好&#xff0c;小编为大家解答python中大于等于且小于等于的问题。很多人还不知道python大于号小于号如何运用&#xff0c;现在让我们一起来看看吧&#xff01; 大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python中大于并小于一个数代码&#xff0c;python 大…

数据结构【线性表篇】(二)

数据结构【线性表篇】(二&#xff09; 文章目录 数据结构【线性表篇】(二&#xff09;前言为什么突然想学算法了&#xff1f;为什么选择码蹄集作为刷题软件&#xff1f; 目录一、单链表(一)、单链表的定义(二)、单链表的建立(三)、单链表的插入删除(四)、单链表的查找 二、主函…

springBoot2.3-基本介绍及入门案例

本次学习雷丰阳springBoot(2.3版本)。建议先修ssm 一、SpringBoot基本介绍 springBoot是当今最为流行的java开发框架。 1、springBoot的底层是spring&#xff0c; 因此继承了spring的粘合其他框架的能力。 2、本质上还是其他框架包括spring在工作 , springBoot起到一个整合其他…

LeetCode刷题--- 黄金矿工

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 ​​​​​​http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​​http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述…
最新文章