迭代器与生成器
一.迭代器
1.什么是迭代器
迭代:更新换代的过程,前一次循环的终止条件是后一次循环的初始条件。
迭代器:迭代取值的过程。
2.为什么要用迭代器
迭代器提供了一种不依赖索引取值的方式
3.怎么用迭代器
可迭代对象(iterable) :有内置方法__iter__ ps:补充:针对双下线开头双下划线结尾的方法,推荐读:双下+方法名
基本类型中的可迭代对象有:str,tuple,list,dict,set和文件对象(文件对象本身就是一个迭代器对象)
str = "12123" lis = [1,2,3,4,5] tup = (1,2,3,4) dic = { "stevin" : "male"} se = { 1,2,3,4} with open("a.txt", "at",encoding="utf-8") as f : print(f.__iter__()) print(str.__iter__()) print(lis.__iter__()) print(tup.__iter__()) print(dic.__iter__()) print(se.__iter__())
迭代器(iterator):具有内置方法__iter__ 和__next__ . ps:迭代器一定是可迭代对象,可迭代对象不一定是迭代器对象。
同时具有内置方法__iter__方法和内置方法__next__的可迭代对象,可以通过__iter__方法得到就是该对象的迭代器对象
迭代器对象无论执行多少次__iter__方法得到的还是迭代器对象本身
迭代器的取值必须使用__next__
迭代器的特点:只能按照次序向后取值,不能后退。
迭代取值:
优点
1.不依赖于索引取值
2.内存中永远只占一份空间,不会导致内存溢出
缺点
1.不能够获取指定的元素
2.取完之后会报StopIteration错
异常处理:当迭代器中的值被取完后,再用__next__取值会报出StopIteration异常
解决方法: try : 报错语句
except StopIteration : 捕获异常后的操作
l = [1,2,3,4] l = l.__iter__() while True : try: print(l.__next__()) except StopIteration : break
二.for循环的本质
for循环内部的本质
1.将in后面的literable对象调用__iter__转换成迭代器对象
2.调用__next__迭代取值
3.内部有异常捕获StopIteration,当__next__执行报错时,自动结束循环
三.生成器
生成器:个人自定义的迭代器,生成器的本质就是迭代器(具有__iter__ 和__next__两个内置方法)
生成器的定义与函数的定义类似,使用yield代替return来进行返回结果。
def func() : print("first") yield 111 #yield后面跟的是调用迭代器__next__方法返回的值 print("second") yield 222,"aaaa","bbbb" print("third") yield 333 print("fourth") yield 444 res = func() # 有yield函数名加(),不会让函数运行 # 而是生成器初始化,把函数变为迭代器对象。 print(res.__next__()) #返回一个值 print(res.__next__()) #以元祖的形式返回多个值 print(res.__next__())
yield外界传参
def dog (name) : print("%s 准备开吃" %name) while True: food = yield print('%s 吃了 %s' % (name, food)) g = dog('stevin') g.__next__() # 必须在运行代码yield时,才能进行传值 g.send('大骨头') # 给yield左边的变量传参 触发了__next__方法 g.send('饺子') g.send('饺子')
生成器表达式:
格式:(变量名 for 变量名 in 容器类型 if 判断条件)
with open("b.txt", "rt",encoding="utf-8") as f : res = (len(line) for line in f) # 生成器表达式 print(sum(res))
生成器不会主动执行任何一行代码,必须通过__next__触发代码的运行
yield
1.帮你提供了一种自定义生成器方式
2.会帮你将函数的运行状态暂停住
3.可以返回值
yield与return的异同点
相同点:都可以返回值,并且都可以返回多个
不同点:
yield可以返回多次值,而return只能返回一次函数立即结束
yield还可以接受外部传入的值
四.内置方法
print(abs(-13.24)) # abs 求绝对值 l = [1,1,0] print(all(l)) # all 存在一个为False就返回False print(any(l)) # any 任意一位为True就返回True def index(): username = '我是局部名称空间里面的username' print(locals()) # locals 返回当前所在区域存储的所有的名字 print(globals()) # globals 无论在哪 返回的都是全局名称空间 index() print(bin(10)) # bin 十进制转2进制 print(oct(10)) # oct 十进制转8进制 print(hex(10)) # hex 十进制转16进制 print(int('0b1010',2)) # 其他进制转十进制 print(bool(1)) print(bool(0)) # bool判断真假 s = 'hello你好' print(s.encode('utf-8')) # encode 编码 print(bytes(s,encoding='utf-8')) # 字节流 def index(): pass print(callable(index)) # callable 可调用的(可以加括号执行相应功能的) print(chr(65)) # chr 将数字转换成ascii码表对应的字符 print(ord('A')) # ord 将字符按照ascii表转成对应的数字 print(dir(range(12))) # dir 获取当前对象名称空间里面的名字 print(divmod(101,10)) total_num,more = divmod(900,11) if more: total_num += 1 print('总页数:',total_num)# divmod 分页器 l = ['a','b','c','d'] for i,j in enumerate(l,1):# enumerate 枚举 print(i,j) # eval exec 执行字符串表达式 s1 = """ print(1 + 2) for i in range(10): print(i) """ # eval(s1) exec(s1) name = 'jason' s2 = """ name """ print(eval(s2)) # eval不支持逻辑代码,只支持一些简单的python代码 def login(): """ 一起嗨皮 :return: """ print(help(login)) # help 查看函数注释 print(isinstance("123",list)) # isinstance 判断对象是否属于某个数据类型 print(pow(2,3)) # 返回 x的y次方。 print(round(3.4)) # round 四舍五入,取整
五.面向过程编程
面向过程编程:类似与流程化设计
好处:
将复杂的问题简单化,流程化
坏处:
可扩展性较差 一旦需要修改 整体都会受到影响
六.面试题
def multipliers(): return [lambda x : i*x for i in range(4)] print([m(2) for m in multipliers()]) # 扩展版 def multipliers2(): list1 = [] for i in range(4): def func(x): #应该这么修改:def func(x, i=i): return x * i list1.append(func) return list1 print([m(2) for m in multipliers2()])
推荐阅读
-
带您阅读 "新一代垃圾收集器 ZGC 的设计与实现 "之一:垃圾收集器概述
-
浙江大学的夏清华:电子皮肤与云、服务器、人工智能算法相结合,将有广泛的应用前景
-
基于 STM32 微控制器的汽车轮胎压力、速度和状态监测系统的设计与实现
-
python 解释器 pycharm 安装与环境变量配置图文教程
-
Fuel Wallet 新版本与 Beta-4 测试网络兼容:浏览器钱包助力生态增长
-
Web 服务器 apache tomcat11-21-监控与管理
-
指针发生器网络(指针发生器网络)原理与实践
-
服务器与前置放大器的区别
-
一种结构设计模式,允许在对象中动态添加新行为。它通过创建一个封装器来实现这一目的,即把对象放入一个装饰器类中,然后把这个装饰器类放入另一个装饰器类中,以此类推,形成一个封装器链。这样,我们就可以在不改变原始对象的情况下动态添加新行为或修改原始行为。 在 Java 中,实现装饰器设计模式的步骤如下: 定义一个接口或抽象类作为被装饰对象的基类。 公共接口 Component { void operation; } } 在本例中,我们定义了一个名为 Component 的接口,该接口包含一个名为 operation 的抽象方法,该方法定义了被装饰对象的基本行为。 定义一个实现基类方法的具体装饰对象。 公共类 ConcreteComponent 实现 Component { public class ConcreteComponent implements Component { @Override public void operation { System.out.println("ConcreteComponent is doing something...") ; } } 定义一个抽象装饰器类,该类继承于基类,并将装饰对象作为一个属性。 公共抽象类装饰器实现组件 { protected Component 组件 public Decorator(Component component) { this.component = component; } } @Override public void operation { component.operation; } } } 在这个示例中,我们定义了一个名为 Decorator 的抽象类,它继承了 Component 接口,并将被装饰对象作为一个属性。在操作方法中,我们调用了被装饰对象上的同名方法。 定义一个具体的装饰器类,继承自抽象装饰器类并实现增强逻辑。 公共类 ConcreteDecoratorA extends Decorator { public ConcreteDecoratorA(Component 组件) { super(component); } } public void operation { super.operation System.out.println("ConcreteDecoratorA 正在添加新行为......") ; } } 在本例中,我们定义了一个名为 ConcreteDecoratorA 的具体装饰器类,它继承自装饰器抽象类,并实现了操作方法的增强逻辑。在操作方法中,我们首先调用被装饰对象上的同名方法,然后添加新行为。 使用装饰器增强被装饰对象。 公共类 Main { public static void main(String args) { Component 组件 = new ConcreteComponent; component = new ConcreteDecoratorA(component); 组件操作 } } 在这个示例中,我们首先创建了一个被装饰对象 ConcreteComponent,然后通过 ConcreteDecoratorA 类创建了一个装饰器,并将被装饰对象作为参数传递。最后,调用装饰器的操作方法,实现对被装饰对象的增强。 使用场景 在 Java 中,装饰器模式被广泛使用,尤其是在 I/O 中。Java 中的 I/O 库使用装饰器模式实现了不同数据流之间的转换和增强。 让我们打开文件 a.txt,从中读取数据。InputStream 是一个抽象类,FileInputStream 是专门用于读取文件流的子类。BufferedInputStream 是一个支持缓存的数据读取类,可以提高数据读取的效率,具体代码如下: @Test public void testIO throws Exception { InputStream inputStream = new FileInputStream("C:/bbb/a.txt"); // 实现包装 inputStream = new BufferedInputStream(inputStream); byte bytes = new byte[1024]; int len; while((len = inputStream.read(bytes)) != -1){ System.out.println(new String(bytes, 0, len)); } } } } 其中 BufferedInputStream 对读取数据进行了增强。 这样看来,装饰器设计模式和代理模式似乎有点相似,接下来让我们讨论一下它们之间的区别。 第三,与代理模式的区别: 代理模式的目的是控制对对象的访问,它在对象外部提供一个代理对象来控制对原对象的访问。代理对象和原始对象通常实现相同的接口或继承相同的类,以确保两者可以相互替换。 装饰器模式的目的是动态增强对象的功能,而这是通过对象内部的包装器来实现的。在装饰器模式中,装饰器类和被装饰对象通常实现相同的接口或继承自相同的类,以确保两者可以相互替代。装饰器模式也被称为封装器模式。 在代理模式中,代理类附加了与原类无关的功能。
-
乘风破浪,迎接腾讯蓝擎套件的现代化研发运维(DevOps),从自研自用到开源赋能,开启智能运营与高效研发迭代的新时代