生成器、迭代器、装饰器

生成器、迭代器、装饰器

  • 生成器
    • 生成器表达式
    • yield
    • 生成器方法
  • 迭代器
  • 装饰器
    • 基本装饰器
    • 带参数装饰器
    • 类装饰器

生成器

生成器是 Python 中一种特殊的迭代器,它不需要一次性将所有值都生成出来,而是可以在需要时逐个生成值,从而节省内存空间,生成器在处理大量数据或需要延迟生成的数据时非常有用。

生成器有两种实现方式,一种是利用生成器表达式,另一种是利用关键字 yield

生成器表达式

x = (i for i in range(5))  # 生成器表达式;x 是生成器对象;[i for i in range(5)] 是列表表达式或列表推导式
print(x)

for i in range(3):
    print(next(x))  # 利用 next 获取生成器对象中的下一个元素;调用一次 next,生成一个值

print(list(x))  # 获取生成器对象中还未生成的值;生成器中所有的值都已生成,这时若再调用 next,会报错
---------
<generator object <genexpr> at 0x0000021F7EC067C8>
0
1
2
[3, 4]


# 生成器还可用于 for 循环中
x = (i for i in range(5))
for i in x:
    print(i)
---------
0
1
2
3
4

yield

生成器可以使用函数和关键字 yield 来定义,yield 语句的作用类似于 return,但不同之处在于它会将值返回给调用者,并暂停生成器的执行,等待下一次调用。

当使用 next() 作用于生成器对象时,函数开始执行,在遇到 yield 时暂停执行,并返回 yield 后面的值;当再次使用 next() 时,函数会从原来暂停的地方继续执行,直到遇到 yield 语句,如果没有 yield 语句,则抛出异常。

def my_generator():
    yield 1
    yield 2
    yield 3

gen = my_generator()  # 创建生成器对象

print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3
---------
<generator object my_generator at 0x0000019D384AE7C8>
1
2
3


# 生成器还可用于 for 循环中,类似于 range(),使得代码更加简洁
for value in gen:
    print(value) 
---------
1
2 
3

生成器方法

生成器比迭代器多 3 个方法,send()、throw()、close()。

send() 可以和 next() 一样用来生成值(即调用 send() 时会从生成器对象中生成值),还可以往生成器内部传递数据,会把数据传递给 yield 前面的变量;使用 send() 之前,生成器对象至少已经通过 next() 生成过一次值。

def generator():
    for i in range(10):
        yield i

gen = generator()

print(gen.send(6))  # 会报错,因为使用 send() 之前还未调用过 next()
def generator():
    for i in range(10):
        x = yield i
        print('send() 传入的数据为:', x)

gen = generator()

next(gen)  # 先调用一次 next(),再调用 send() 时便不会报错

print(gen.send(11))  # 传入的 11 会赋值给 yield 前面的变量 x;同时会从生成器对象中生成一个值
print(gen.send(12))
print(gen.send(13))
---------
send() 传入的数据为: 11
1
send() 传入的数据为: 12
2
send() 传入的数据为: 13
3
def generator():
    host = yield
    for i in range(10):
        host = yield f'https://{host}/user/login'

gen = generator()

next(gen)

print(gen.send('www.baidu.com'))
print(gen.send('www.csdn.net'))
print(gen.send('www.github.com'))
---------
https://www.baidu.com/user/login
https://www.csdn.net/user/login
https://www.github.com/user/login

throw() 方法表示在生成器中抛出异常,效果等同于 raise。

close() 方法关闭生成器,关闭后再使用 next() 会报错。

迭代器

在 Python 中,迭代器(Iterator)是一个可以逐个访问元素并在需要时生成元素的对象。它具有两个基本方法:__iter__()__next__()

  • __iter__() 方法返回迭代器对象本身。这使得迭代器可以在循环中使用,并且可以在需要时通过 iter() 函数进行迭代。
  • __next__() 方法返回迭代器的下一个元素。如果没有更多的元素可供返回,则引发 StopIteration 异常。

迭代器通常与可迭代对象一起使用。可迭代对象是一类具有 __iter__() 方法的对象,该方法返回一个迭代器。例如,列表、元组、集合和字典都是可迭代对象,因为它们都具有 __iter__() 方法,可以返回一个迭代器。生成器也是一种特殊类型的迭代器。

迭代器的工作原理是通过维护一个内部状态来记录当前位置,并且在每次调用 __next__() 方法时更新状态以返回下一个元素。这使得迭代器能够按需生成元素,而不必一次性将所有元素加载到内存中。

__iter__()iter() 都可用来创建迭代器。

  1. __iter__() 方法:
    • __iter__() 是一个特殊方法(或称为魔术方法),用于定义一个对象是可迭代的。
    • 当对象需要支持迭代操作时,可以在其类中实现 __iter__() 方法,该方法应返回一个迭代器对象。
    • 这个方法被内置的 iter() 函数隐式调用,用于获取对象的迭代器。
  2. iter() 函数:
    • iter() 是一个内置函数,用于获取可迭代对象的迭代器。
    • 当你需要迭代访问一个可迭代对象(例如列表、元组、集合、字典等)时,可以使用 iter() 函数获取其迭代器。
    • iter() 函数接受一个可迭代对象作为参数,并返回该对象对应的迭代器。

区别总结:

  • __iter__() 方法是在类中实现的,用于将对象定义为可迭代的,并且应该返回一个迭代器对象。
  • iter() 函数是一个内置函数,用于获取可迭代对象的迭代器。

在实际应用中,通常不直接调用对象的 __iter__() 方法,而是使用 iter() 函数来获取迭代器。例如,可以使用 iter() 函数来迭代访问列表、元组、集合、字典等数据类型。

__next__() 方法和 next() 函数都是用于获取迭代器的下一个元素,但它们有以下区别:

  1. __next__() 方法:
    • __next__() 方法是迭代器对象内部的一个特殊方法(或称为魔术方法),用于返回迭代器的下一个元素。
    • 在自定义迭代器类中,需要实现 __next__() 方法以定义迭代器的行为。
    • 如果迭代器没有更多的元素可供返回,则 __next__() 方法应该引发 StopIteration 异常。
  2. next() 函数:
    • next() 是一个内置函数,用于从迭代器中获取下一个元素。
    • 它接受一个迭代器作为参数,并返回该迭代器的下一个元素。
    • 如果迭代器没有更多的元素可供返回,则 next() 函数会引发 StopIteration 异常。

区别总结:

  • __next__() 方法是迭代器对象内部的方法,用于返回迭代器的下一个元素。
  • next() 函数是一个内置函数,用于从迭代器中获取下一个元素。

在实际应用中,通常使用 next() 函数来从迭代器中获取下一个元素,而不是直接调用迭代器的 __next__() 方法。这是因为 next() 函数更加方便,并且能够处理 StopIteration 异常,使代码更加健壮。

a = [i for i in range(1, 6)]  # 列表,可迭代对象
b = (10, 20, 30)  # 元组,可迭代对象

a_iter = iter(a)  # 参数为可迭代对象(列表、元组、字典、集合、字符串、文件对象等);使用 iter() 函数时会调用 __iter__() 方法;返回迭代器
b_iter = b.__iter__()  # 直接调用 __iter__() 方法,返回迭代器

print(a_iter)
print(b_iter)

print(next(a_iter))  # 参数为迭代器(包括生成器);使用 next() 函数时会调用 __next__() 方法;生成一个值
print(b_iter.__next__())  # 直接调用 __next__() 方法,生成一个值
---------
<list_iterator object at 0x000001E4A9FEAAC8>
<tuple_iterator object at 0x000001E4AA0F6748>
1
10

装饰器

基本装饰器

Python 装饰器是一种高级语法,它可以在不修改原函数代码的情况下,增加或改变原函数的功能。装饰器本质上是一个函数,它可以接收一个函数作为参数,并返回一个新的函数。装饰器通常用于添加功能,例如日志记录、性能测试、权限检查等。

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()
---------
Something is happening before the function is called.
Hello!
Something is happening after the function is called.

在这个示例中,my_decorator 是一个装饰器函数,它接受一个函数 func 作为参数,并返回一个内部函数 wrapperwrapper 函数在调用原始函数之前和之后执行一些操作。通过在 say_hello 函数上面加上 @my_decorator,我们告诉 Python 在调用 say_hello 函数之前先将其传递给 my_decorator 函数。

除了上述基本的装饰器外,还有一些高级用法,例如带参数的装饰器、类装饰器等。使用装饰器可以使代码更加简洁、可读,并且使功能模块化,提高了代码的可维护性和可重用性。

带参数装饰器

def my_decorator_with_args(arg1, arg2):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f"Decorator arguments: {arg1}, {arg2}")
            print("Something is happening before the function is called.")
            result = func(*args, **kwargs)
            print("Something is happening after the function is called.")
            return result
        return wrapper
    return decorator

@my_decorator_with_args("arg1_value", "arg2_value")
def say_hello(name):
    print(f"Hello, {name}!")

say_hello("Alice")
---------
Decorator arguments: arg1_value, arg2_value
Something is happening before the function is called.
Hello, Alice!
Something is happening after the function is called.

在这个示例中,my_decorator_with_args 是一个带参数的装饰器工厂函数,它接受两个参数 arg1arg2。返回的实际装饰器函数 decorator 接受被装饰的函数 func,并返回内部函数 wrapper。在 wrapper 函数内部,我们可以访问装饰器的参数 arg1arg2,并在调用原始函数之前和之后执行一些操作。

当我们使用 @my_decorator_with_args("arg1_value", "arg2_value") 来装饰 say_hello 函数时,实际上是先调用 my_decorator_with_args("arg1_value", "arg2_value"),返回一个装饰器函数,然后将 say_hello 函数传递给该装饰器函数进行装饰。

最后,当我们调用 say_hello("Alice") 时,装饰器内部的 wrapper 函数将会被执行,同时将参数传递给原始函数。

类装饰器

类装饰器是指实现了 __call__ 方法的类,它可以像函数一样被调用,并且可以接受一个函数作为参数,返回一个新的函数。

class MyDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("Something is happening before the function is called.")
        result = self.func(*args, **kwargs)
        print("Something is happening after the function is called.")
        return result

@MyDecorator
def say_hello():
    print("Hello!")

say_hello()
---------
Something is happening before the function is called.
Hello!
Something is happening after the function is called.

在这个示例中,MyDecorator 类实现了 __call__ 方法,这意味着它可以像函数一样被调用。在 __init__ 方法中,它接受一个函数 func 作为参数,并将其保存为实例属性。在 __call__ 方法中,它执行装饰器的功能,即在调用原始函数之前和之后执行一些操作。

通过将 @MyDecorator 应用到 say_hello 函数上,我们实际上创建了一个 MyDecorator 的实例,并将 say_hello 函数传递给它的 __init__ 方法。然后,当我们调用 say_hello() 时,MyDecorator 实例的 __call__ 方法将被调用,从而实现了装饰器的功能。

类装饰器的优点之一是可以更方便地维护状态信息,因为可以将状态信息存储在类的实例属性中。此外,类装饰器还可以更容易地实现一些高级功能,例如接受装饰器参数、实现装饰器链等。

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

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

相关文章

一次网卡驱动BUG故障的排错历程

前言 在日常运维中&#xff0c;总会遇到一些棘手的故障或问题&#xff0c;尤其面临多系统融合的兼容性或一些融合节点可能存在未知bug等方面&#xff0c;排错难度都会增加。 本文将从一次小事件为入口进行延伸&#xff0c;将宿主机esxi基础系统的多融合节点故障的排错历程展开…

分布式监控平台---Zabbix

一、Zabbix概述 作为一个运维&#xff0c;需要会使用监控系统查看服务器状态以及网站流量指标&#xff0c;利用监控系统的数据去了解上线发布的结果&#xff0c;和网站的健康状态。 利用一个优秀的监控软件&#xff0c;我们可以&#xff1a; 通过一个友好的界面进行浏览整个…

C/C++ C/C++ 入门(6)模板初阶

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;C 多多指教&#xff01; 一、泛型编程 在之前&#xff0c;我们进行编程的时候&#xff0c;总是针对于某一个具体的问题。就比如说&#xff0c;如何实现一个int类型的swap函数呢&#xff1f;大家肯定会写。…

MySQL 表管理

目录 建库 语法&#xff1a; 库名命名规则&#xff1a; 相关命令&#xff1a; 建表 语法&#xff1a; 相关命令&#xff1a; 修改表 语法&#xff1a; 常用操作命令 复制表 数据类型 MySQL的10种常用数据类型&#xff1a; 数据的导入和导出 导入&#xff1a; 格…

iptables 学习

文章目录 iptables 学习iptables基本组件&#xff1a;常用iptables命令&#xff1a;iptables -L 输出及解释解释&#xff1a; iptables “奇淫巧技”端口转发&#xff08;port forwarding&#xff09;流量重定向到透明代理防止DDoS攻击防止SYN洪泛攻击黑名单使用状态模块跟踪连…

第14届java A组蓝桥杯做题记录

A题 特殊日期 package Java14省赛.Java研究生组;import java.time.Year; //特殊判断一下2月份&#xff0c;leaf 为true 1 import java.util.*;import 蓝桥杯.dfs_n皇后; public class 特殊日期 {static int sum(int d){int res 0;while(d > 0){res d % 10;d / 10;}return…

基于Springboot+Vue的Java项目-房产销售系统(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…

FlexLua低代码便捷打造4G转RS485网关设备

在物联网时代&#xff0c;各种设备之间的互联互通变得越来越重要&#xff0c;而4G转RS485网关设备的出现为不同设备之间的通信提供了更便捷的方式&#xff0c;推动了物联网技术的发展。 4G转RS485网关的通信原理相对简单易懂。它通过4G网络接收数据&#xff0c;然后将数据转换成…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之十三 简单去除图片水印效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之十三 简单去除图片水印效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之十三 简单去除图片水印效果 一、简单介绍 二、简单去除图片水印效果实现原理 三、简单去除图片水印效果案例…

Java入门基础知识第八课(数组)——冒泡排序、Arrays工具类

前面二白讲了关于数组的概念、语法以及简单的输入输出&#xff0c;实际上关于数组的知识还有很多&#xff0c;接下来咱们讲一下冒泡排序以及一些常用的Arrays工具类&#xff0c;需要记忆的知识很多&#xff0c;而且容易混淆。 一、冒泡排序 简介&#xff08;原理&#xff09;…

基于SpringBoot的“银行OA系统的设计与实现”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“银行OA系统的设计与实现”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 用户登录界面 管理员主界面 员工基本档…

知道做到 一篇总结学习方法的笔记

元数据 [!abstract] 知道做到&#xff1a;跃迁式学习 书名&#xff1a; 知道做到&#xff1a;跃迁式学习作者&#xff1a; 彼得•霍林斯简介&#xff1a; 学习是改善你的生活环境、成为你想成为的人的关键。科学的方法能加速学习进程&#xff0c;让你事半功倍。技能、信息和能力…

openkylin系统通过网线连接ubuntukylin系统上网攻略

openkylin系统通过网线连接ubuntukylin系统上网攻略 主机1&#xff1a;x64 amd &#xff0c;系统&#xff1a;ubuntukylin 22.04 &#xff0c;状态&#xff1a;通过wifi连接热点进行上网&#xff0c;并共享网络。 主机2&#xff1a;x64 intel &#xff0c;系统&#xff1a;ope…

5.x 版本 CallKit SDK 无法弹起通话界面

5.x 版本 CallKit SDK 作为接听方在前台的情况下无法弹起通话界面&#xff0c;作为拨打方能正常弹起通话界面 分析&#xff08;根因分析、需求分析&#xff09; CallKit SDK 初始化依赖于 IMKit SDK 初始化&#xff0c;如果您使用 IMLib SDK 的方法初始化的话&#xff0c;会导…

告别百年激进笔记

系列文章目录 八次危机笔记 告别百年激进笔记 文章目录 系列文章目录前言导图第一部分 资本全球化的宏大叙事第一节 人类创造的两个异化物第二节 全球资本化与制度性致贫第三节 国家竞争的“微笑曲线”第四节 欧债危机实属政治危机第五节 日本研究中的另类思考第六节 从…

流程图的新语法-mermaid的快速使用--推荐

chatgpt或者现在的大数据采用的流程图给出的代码如下&#xff1a; graph TD;A[接收客户请求] --> B[问题分类];B --> C[技术支持];B --> D[维修服务];C --> E[远程解决];C --> F[现场支持];D --> G[维修完成];G --> H[服务反馈];style A fill:#f9f,strok…

【数据结构与算法】贪心算法及例题

目录 贪心算法例题一&#xff1a;找零问题例题二&#xff1a;走廊搬运物品最优方案问题输入样例例题三&#xff1a;贪心自助餐 贪心算法 贪心算法是一种在每一步选择中都采取当前状态下最优的选择&#xff0c;以期望最终达到全局最优解的算法。它的核心思想是每次都选择当前最…

即插即用模块详解SCConv:用于特征冗余的空间和通道重构卷积

目录 一、摘要 二、创新点说明 2.1 Methodology 2.2SRU for Spatial Redundancy​编辑 2.3CRU for Channel Redundancy 三、实验 3.1基于CIFAR的图像分类 3.2基于ImageNet的图像分类 3.3对象检测 四、代码详解 五、总结 论文&#xff1a;https://openaccess.thecvf.c…

kafka的概念以及Zookeeper集群 + Kafka集群 +elfk集群

目录 zookeeper同步过程 分布式通知和协调 zookeeper同步过程 分布式通知和协调 准备 3 台服务器做 Zookeeper 集群 192.168.68.5 192.168.68.6 192.168.68.7 安装前准备 //关闭防火墙 systemctl stop firewalld systemctl disable firewalld setenforce 0 node1服务器&a…

Linux进阶篇:性能监控工具:socket 统计信息

Linux性能监控工具&#xff1a;socket 统计信息 1 ss命令介绍 ss 是 Socket Statistics 的缩写。ss 命令可以用来获取 socket 统计信息&#xff0c;它显示的内容和 netstat 类似。但 ss 的优势在于它能够显示更多更详细的有关 TCP 和连接状态的信息&#xff0c;而且比 netsta…
最新文章