迭代器、for循环本质、生成器、常用内置方法整理
迭代器
什么是迭代器
迭代:更新换代(重复)的过程,每次的迭代都必须基于上一次的结果
迭代器:迭代取值的工具
为什么要用迭代器
迭代器给你提供了一种不依赖索引取值的方式
重复+每次迭代都是基于上一次的结果而来的
l = [1, 2, 3, 4] s = 'hello' n = 0 while n < len(s): print(s(n)) n+=1
根据我们知道的数据类型中,其中 字符串(str)、列表(list)、元组(tuple)、字典(dict)、集合(set)、文件对象 都属于需要迭代取值的数据类型,内置有__iter__方法的都叫做可迭代对象
文件对象(执行内置的__iter__之后还是本身,没有任何变化):文件对象本身就是迭代器对象
迭代器对象
1.内置有__iter__方法
2.内置有__next__方法
注意:迭代器一定是可迭代对象,而可迭代对象不一定是迭代器对象
列表取值
l = [1,2,3,4] iter_l = l.__iter__() #生成一个迭代器对象 #迭代器取值,调用__next__方法 print(iter_l.__next__()) #取值:1 print(iter_l.__next__()) #取值:2 print(iter_l.__next__()) #取值:3 print(iter_l.__next__()) #取值:4 print(iter_l.__next__()) #当列表中的值被取完时,直接报错StopIteration
字典取值
d = {'name':'zhangsan', 'password':'123', 'hobby':'study'} #将可迭代对象d转换成迭代器对象 iter_d = d.__iter__() #迭代器对象取值,使用__next__ print(iter_d.__next__()) #取值:name print(iter_d.__next__()) #取值:password print(iter_d.__next__()) #取值:hobby print(iter_d.__next__()) #当字典中的key被取完时,直接报错StopIteration
在项目过程中,所有的程序肯定是不允许有报错信息的,这时我们可以使用捕获异常来处理
while True: try: print(iter_d.__next__()) except StopIteration: #放入程序的报错信息 print('值已经被取完了') break
ps:迭代器取值的特点:只能从前往后依次取,不能倒序
for循环内部的本质
for循环内部的本质
1.将in后面的对象调用__iter__转换成迭代器对象
2.调用__next__迭代取值
3.内部有异常捕获StopIteration,当__next__报这个错,自动结束循环
d = {'name':'zhangsan', 'password':'123', 'hobby':'study'} for i in d: print(i) #for循环后面的in是关键,跟的是一个可迭代对象
小示例:
#使用匿名函数,以及map方法求取出的值 l = [1,2,3,4] res = map(lambda x:x+1,l) print(map(lambda x:x+1,l)) print(res.__next__()) print(res.__next__()) print(res.__next__()) print(res.__next__()) #打印结果 2 3 4 5
小结:
可迭代对象:内置有__iter__方法
迭代器对象:内置既有__iter__方法,内置也有__next__方法
迭代取值:
优点:
1.不依赖于索引取值
2.内存中永远只占一份空间,不会导致内存溢出
缺点:
1.不能够获取指定的元素
2.取完之后会报错StopIteration
生成器
生成器:用户自定义的迭代器
def func(): print('first') yield 666 # 函数内如果有yield关键字,那么加括号执行函数的时候并不会触发函数体代码的运行 print('second') yield 777 print('third') yield 888,999 print('forth') yield g = func() # 生成器初始化:将函数变成迭代器 print(g) print(g.__next__()) print(g.__next__()) print(g.__next__())
打印结果:
<generator object func at 0x000001F4D0F73780>
first
666
second
777
third
(888, 999)
# yield后面跟的值就是调用迭代器__next__方法能得到的值
# yield既可以返回一个值,也可以返回多个值,并且多个值也是按照元组的形式返回
小练习:
有这样一个例子,如何把它写成一个生成器呢?
for i in range(1,10,2):
print(i)
def my_range(start,end,step=2): # 定义三个形参 while start < end: yield start # 返回start的值 start += step #每次循环start都加上step的值 for j in my_range(1,10,2): print(j)
yield的用法
yield支持外界为其传参
def eat(name): print('%s 准备开吃' %name) while True: food = yield print('%s 吃了 %s' %(name, food)) g = eat('zhangsan') g.__next__() # 必须现将代码运行至yield,才能够为其传参 g.send('包子') #send给yield左边的变量传值,其中触发了__next__方法 g.send('火腿') # 打印结果 zhangsan 准备开吃 zhangsan 吃了 包子 zhangsan 吃了 火腿 # 当函数内有yield关键字的时候,调用该函数不会执行函数体代码,而是将函数变成生成器
小结:
yield:
1.提供了一种自定义生成器方式
2.会帮助将函数的运行状态暂停住
3.可以返回值
与return之间异同点
相同点:都可以返回值,并且都可以返回多个
不同点:
1.yield可以返回多次值,而return只能返回一次函数就会立即结束
2.yield还可以接收外部传入的值
生成器生成式
生成器不会主动执行任何一行代码,必须通过__next__触发代码的运行
with open('xxx.txt','r',encoding='utf-8') as f: g = (len(line) for line in f) print(sum(g)) #求和
练习
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循环g=(add(n,i) for i in (add(n,i) for i in test())) print(n) res=list(g) print(res) res的结果是多少
答案
[20,21,22,23]
内置方法
abs:绝对值
print(abs(-11.11)) # 求绝对值 l = [0,1,0] print(all(l)) # 只要有一个为False就返回False print(any(l)) # 只要有一个位True就返回True
callable :可调用的(可调用返回True,不可调用返回False)
l = [1,2,3] def index(): pass print(callable(l)) print(callable(index))
# print(chr(97)) # 将数字转换成ascii码表对应的字符 # print(ord('a')) # 将字符按照ascii表转成对应的数字
dir:获取当前对象名称空间里面的名字
l = [1,2,3] print(dir(l))
divmod:分页器
print(divmod(101,10)) total_num,more = divmod(900,11) if more: total_num += 1 print('总页数:',total_num)
enumerate:枚举
l = ['a','b'] for i,j in enumerate(l,1): print(i,j)
eval
s = """ print('hello baby~') """ eval(s) # 打印结果 hello baby~
s1 = """
print(1 + 2)
for i in range(10):
print(i)
"""
eval(s1)
# 报错:SyntaxError: invalid syntax
# eval不支持逻辑代码,只支持一些简单的python代码
exec
s1 = """ print(1 + 2) for i in range(10): print(i) """ exec(s1)
# 打印结果
1
2
3
4
5
6
7
8
9
format 三种玩法
{}占位
{index} 索引
{name} 指名道姓
isinstance:判断是否属于某个数据类型
n = 1 print(type(n)) print(isinstance(n,int)) # 打印结果 <class 'int'> True
print(pow(2,3)) #2的三次方 # 打印结果 8
print(round(3.4)) #四舍五入 # 打印结果 3
help:打印函数注释
def login(): """ 一起嗨皮 :return: """ print(help(login))