函数 迭代器,生成器



# 一 迭代器

'''
什么是迭代器:
迭代:就是一个重复的过程,每次的迭代都必须基于上一次的结果
迭代器:就是可以迭代取值的工具

重点:迭代器不是简单的重复,而是重复+每一次迭代都是基于上一次的结果而来的



特点:那我们为什么要用迭代器:
因为迭代器给我们提供了一种不依赖于索引取值的方式


1.什么是可迭代对象:只有内置有__iter__方法的都叫做可迭代对象


2.在基本的数据类型中,是可迭代对象的有:
str ,list,tuple,dict,set

3.但是如果在文件对象中(执行内置的__iter__之后还是本身,没有任何变化):因为文件对象本身就是迭代器对象


重点:如果可迭代对象执行内置的__iter__方法得到的就是该对象的迭代器对象

案例:
res = s.__iter__() # res = iter(s)
print(s.__len__()) # 简化成了len(s)
res1 = l.__iter__() # res1 = iter(l)
res2 = f1.__iter__() # res2 = iter(f1)



迭代器对象
1.内置有__iter__方法
2.内置有__next__方法(可以通过这个取值)
注意点:迭代器一定是可迭代对象
而可迭代对象不一定是迭代器对象


那么如何生成一个迭代器对象?
举例:
l = [1,2,3,4]
可以用__iter__方法来生成一个迭代器对象:
iter_l = l.__iter__()#这样就生成了一个迭代器对象

如果我们想要迭代器取值的话,就需要调用 __next__方法了

print(iter_l.__next__())
一次只会取一个值,还要取的话,要在调用__iter__方法
print(iter_l.__next__())
print(iter_l.__next__())
print(iter_l.__next__())
print(iter_l.__next__())

注意:l 列表中只有4个值,但是我取了五次,已经没有值了,
那么第五次就会报错

如何来解决这个问题:我们可以用异常捕获来解决
案例:
# 异常处理
while True:
try:
print(iter_l.__next__())
except StopIteration:
print('老母猪生不动了')
break

重点:
1.迭代器对象取值的时候必须,必须调用__iter__方法来取值,而且一次只能取一次,取几次调用几次
2.迭代器对象无论执行多少次__iter__方法得到的都是迭代器对象本身
f1 = open('xxx.txt','r',encoding='utf-8')
调用f1内置的__iter__方法
iter_f = f1.__iter__()
print(iter_f is f1)
print(f1 is f1.__iter__().__iter__().__iter__().__iter__())
3.迭代器取值的时候,只能往后依次取,不能后退



重点:__iter__方法就是用来帮我们生成迭代器对象的,
而文件对象本身就是迭代器对象,为什么内置还有__iter__方法

案例:
d = {'name':'jason','password':'123','hobby':'泡m'}
iter_d = d.__iter__()
print(d.__iter__().__next__())
print(d.__iter__().__next__())
print(d.__iter__().__next__())
如果这样写的话,打印出来的结果都是 name
因为他每一次取值的时候,都重新初始化的这个迭代器对象


案例:
l = [1,2,3,4,5]
iter_l = l.__iter__()

print(iter_l.__next__())
print(iter_l.__next__())
print(iter_l.__next__())
print(iter_l.__next__())
print(iter_l.__next__())
# print(iter_l.__next__())# 会报错,值取完了

# 可以通过异常处理来解决
while True:
try:
print(iter_l.__next__()) # 可以捕获错误
except StopIteration:
print('取完了')
break
'''



# 二 生成器

'''
生成器:就是用户自定义的迭代器,其实本质上就是迭代器
注意点:
1.如果函数内有yield关键字,那么加括号执行函数的时候就不会触发函数体的代码运行
2.yield后面要是有返回值,就是可以通过调用__next__方法能得到的值
3.yield可以返回一个或者多个值,返回多个值是按照元组的方式返回

案例:
# def func():
# print('zy')
# yield 1111
# print('egon')
# yield 2222
# print('tank')
# yield 3333
# print('jason')
# yield # 如果下面调用的话 返回None
# yield # 如果下面调用的话 返回None
#
# # g = func()
# # print(g)# 运行的结果 <generator object func at 0x000001E25E3AEFC0>
# g = func()# 生成器初始化:将函数变成迭代器
# print(g)
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())



yield
1.帮你提供了一种自定义生成器方式
2.会帮你将函数的运行状态暂停住
3.可以返回值

与return之间异同点
相同点:都可以返回值,并且都可以返回多个
不同点:
yield可以返回多次值,而return只能返回一次函数立即结束
yield还可以接受外部传入的值


案例:自己写一个简单的range
def my_range(start,end,step=1):
while start < end:
yield start
start += step
for j in my_range(1,100,2):
print(j)


'''


# 三 for 循环的本质

'''
d = {'name':'jason','password':'123','hobby':'泡m'}
for i in d:
print(i)
for 循环后面的in 跟的是一个可迭代对象


for 循环内部的本质
1.将 in 后面的对象调用__iter__转换成迭代器对象
2.调用__next__迭代取值
3.内部有异常捕获StopIteration,当__next__报错时,会自动结束循环

可迭代对象:内置有__iter__方法
迭代器对象:内置有__iter__方法 也有__next__方法

迭代取值:
优点:
1.不依赖于索引取值
2.内存中永远都只占一份空间,不会导致内存溢出

缺点:
1.不能获取指定的元素
2.值取完的时候会报StopIteration错

案例:
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__())
'''

# 四 生成器表达式
'''
生成器不会主动执行任何一行代码,
必须通过__next__触发代码的运行

案例:生成器表达式
res = (i for i in range(1,1000) if i !=4)
print(res)

print(res.__next__())
print(res.__next__())
print(res.__next__())

'''
# 五 常用的一些内置函数
'''
print(abs(-11.11)) # 求绝对值


print(all(l)) # 只要有一个为False就返回False
print(any(l)) # 只要有一个位True就返回True

print(locals()) # 当前语句在哪个位置 就会返回哪个位置所存储的所有的名字
print(globals()) # 无论在哪 查看的都是全局名称空间


print(chr(97)) # 将数字转换成ascii码表对应的字符
print(ord('a')) # 将字符按照ascii表转成对应的数字


callable 查看函数是否可调用


dir获取当前对象名称空间里面的名字


index 索引

enumerate 枚举


format 三种玩法
{}占位
{index} 索引
{name} 指名道姓

isinstance 后面统一改方法判断对象是否属于某个数据类型

print(isinstance(n,list)) # 判断对象是否属于某个数据类型

print(pow(2,3))# 2的三次方


print(round(5.3))# 取整数,可以四舍五入
'''
posted @ 2019-07-15 21:18  ZHANGYUZY  阅读(126)  评论(0编辑  收藏  举报