一、迭代器
什么是迭代:更新换代的过程,每次的迭代都必须基于上一次的结果
迭代器:迭代取值的工具
为什么要用迭代器:迭代器给你提供了一种不依赖于索引取值的方式
1.可迭代对象:内置有__iter__方法的对象,是可迭代对象object.__iter__
基本数据类型中:是可迭代对象的有:
str,list,set,dict,tuple
'hello'.__iter__
(1,2,3).__iter__ 等等
2.迭代器对象
可迭代对象执行object.__iter__()得到的结果就是迭代器对象
迭代器对象既有__iter__方法又有__next__方法
文件对象(执行内置的__iter__之后还是本身 没有任何变化):文件本身就是迭代器对象
迭代器对象一定是可迭代对象,可迭代对象不一定是迭代器对象
迭代器取值 调用__next__
l = [1,2,3,4]
l1 = l.__iter__() #变成迭代器对象了
print(l1.__next__()) #1
print(l1.__next__()) #2
print(l1.__next__()) #3
print(l1.__next__()) #4
print(l1.__next__()) #取值完了,就会报错
#__next__逐一取值
迭代器对象无论执行多少次__iter__方法得到的还是迭代器对象本身
迭代器取值的特点:只能往后依次取,不能后退
迭代取值:
优点:
1.不依赖于索引取值 2.内存中永远只占一份空间,不会导致内存溢出
缺点:
1.不能获取指定的元素 2.取完之后会报StopIteration错误
二、for 循环的本质(重点)
for循环后面的in关键字后面跟的是一个可迭代对象
for循环内部的本质:(很重要)
1.将in后面的可迭代对象调用__iter__变成迭代器对象
2.调用__next__迭代取值
3.内部有异常捕获StopIteration,当__next__报这个错时,自动结束循环
三、生成器
生成器:就是用户自定义的迭代器,本质是迭代器。
函数内部加了关键字yield就变成生成器,有yield关键字,那么加括号执行函数的时候不会触发函数体代码运行。yield后面的值需要调用__next__方法你才能获取到,运行到yield时候,运行会暂停。还需要下一个yield后面的值,你就还需要写一个__next__去获取。
yield既可以返回一个值也可以返回多个值,多个值也是按照元组的形式返回
def index():
print('index')
yield 666
yield 777,888
g = index() #生成器初始化:将函数变成迭代器
print(g.__next__())
print(g.__next__())
#结果
#index
#666
#(777,888)
四、yield表达式形式(支持外界为其传参) send方法
当函数内有yield关键字的时候,调用该函数不会执行函数体代码,而是将函数变成生成器。
用__next__是代码运行到yield暂停下来,返回yield的值,在这里yield没有值,等着我们传入。g.send(),传入的值给左边的变量,并且触发了__next__方法,然后又运行到yield暂停下来。
def dog(name): print('%s 准备开吃'%name) while True: food = yield print('%s 吃了 %s'%(name,food)) g= dog('wee') g.__next__() ## 必须先将代码运行至yield 才能够为其传值 g.send('狗不理包子') # 给yield左边的变量传参 触发了__next__方法 g.send('饺子') #结果 wee 准备开吃 wee 吃了 狗不理包子 wee 吃了 饺子
总结:
yield:
1.帮你提供了一种自定义生成器方式
2.会帮你将函数的运行暂停下来
3.会有返回值
与return的异同点:
相同点:都有返回值,并且都可以返回多个
不同点:yield可以返回多次值,return只能返回一次值就结束函数。yield还可以接受外部传入的值
五、生成器表达式
生成器代码不会主动执行任何一行代码 必须通过__next__触发代码的运行
注意:for 在()里面就是一个生成器表达式,不会触发__next__方法(重点!!!!)
res = (i for i in range(1,100000000) if i != 4) print(res) #是一个生成器 print(res.__next__()) #1 print(res.__next__()) #2
面试题:生成器的运用
def add(n,i):
return n+i
def test(): for i in range(4): yield i g=test() for n in [1,10]: g=(add(n,i) for i in g) # 第一次for循环g=(add(n,i) for i in test()) #第一次循环不会运行,for在()括号里面,这是一个生成器表达式,n = 1 # 第二次for循环g=(add(n,i) for i in (add(n,i) for i in test())) #这里也是一个生成器表达式,n = 10 print(n) #所以后面的n都是等于10 res=list(g) ---------------------------------------------------------------
解析:
n = 10
解析:第二次for循环
第一步:放在list中就有__next__方法,可以变成
g = for i in (add(n,i) for i in test())
add(n,i)
第二步:
然后里面还可以拆开: for i in test() >>> (0,1,2,3)
add(n,i) >>>(10,11,12,13)
第三步:
g = for i in (10,11,12,13)
add(n,i) >>> (20,21,22,23)
res = list(g) >>> [20,21,22,23]
#最后结果返回的答案是什么 #A. res=[10,11,12,13] #B. res=[11,12,13,14] #C. res=[20,21,22,23] 答案 #D. res=[21,22,23,24]
六、内置函数
1. abs() #求绝对值
print(abs(-1.11)) #1.11
2. all()/any()
l = [0,1,2] #因为0是属于False print(all(l)) # 只要有一个为False就返回False print(any(l)) # 只要有一个位True就返回True #False #True
3.chr()/ord() 应用: 在创建验证码的时候可以用
print(chr(97)) # 将数字转换成ascii码表对应的字符 print(ord('a')) # 将字符按照ascii表转成对应的数字 #a #97
4.dir() 可以调用当前对象的所有内置方法和魔法方法
# dir获取当前对象名称空间里面的名字 l = [1,2,3] print(dir(l))
5.divmod() 应用:可以做分页器
返回值(商,余数)
print(divmod(101,10)) #(10, 1)
6.enumerate() 枚举
# enumerate 枚举 l = ['a','b'] for i,j in enumerate(l,1): #设置起始值为1,默认为0 print(i,j) # 1 a # 2 b
7.eval()/exec() 把字符串的外面引号去掉,然后运行代码返回结果。注意eval()不支持逻辑代码,只支持简单python代码
s = """ print('hello baby~') x = 1 y = 2 print(x + y) """ # eval(s) exec(s) #结果 hello baby~ 3
8.isinstance() 判断对象是否属于某个数据类型
n = 1 print(type(n)) print(isinstance(n,list)) # 判断对象是否属于某个数据类型 #判断n是否属于list类型