迭代器 & 生成器

迭代器

# 什么是迭代器    
	迭代:更新换代的过程,每次迭代都必须基于上一次的结果    
	迭代器:迭代取值的工具

# 为什么要用:    
	迭代器提供不依赖于索引取值的方式
# l = [1,2,3,4,5]
# # 生产一个迭代器对象
# iter_l = l.__iter__()
# # 迭代器取值 调用__next__
# print(iter_l.__next__())
# print(iter_l.__next__())
# print(iter_l.__next__())
# print(iter_l.__next__())
# print(iter_l.__next__())      # 如果取完了,直接报错

可迭代对象

# 可迭代对象   
	只要内置有__iter__方法的都叫做可迭代对象
# 基本数据类型中    
	是可迭代对象的有:        
	str list tuple dict set         
	文件对象(执行内置的__iter__之后还是本身 没有任何变化):文件对象本身就是迭代器对象
## 补充:
# 针对双下线开头双下划线结尾的方法,推荐读:双下+方法名
__iter__()	等价于 iter()
__len__()	等价于 len()
__next__()  等价于 next()
# s = [1,2,3,4,5]
# print(s.__len__())
# iter(s)
#
# res = s.__iter__()   # 等价于 res = iter(s)
# print(s.__len__())   # 等价于 len(s)

迭代器对象

# 迭代器对象    
	1.内置有__iter__方法    
	2.内置有__next__方法    
	ps: 迭代器对象一定是可迭代对象    
	而可迭代对象不一定是迭代器对象    
	
# 迭代器取值特点:  
	优点:
	1.不依赖与索引取值
	2.内存中永远只占用一份空间,不会导致内存溢出
缺点:
1.不能够获取指定的元素,迭代器只能从头开始
2.取完之后会报StopIteration错
d = {'name':'jason','password':'123','hobby':'泡m'}
# # 将可迭代对象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__())            # 当取完了报错:StopIteration


# 迭代器对象无论执行多少次__iter__方法得到的还是迭代器对象本身
print(f1 is f1.__iter__().__iter__().__iter__().__iter__())
f1 = open('xxx.txt','w',encoding='utf-8')
# # 调用f1的内置的__iter__
iter_f = f1.__iter__()
print(iter_f is f1)             # True


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

# 答:为了支持for循环

异常捕获处理

# 捕获错误异常处理,当使用__next__取值,取完了依然不报错
d = {'name':'jason','password':'123','hobby':'泡m'}
iter_d = d.__iter__()

while True:
    try:
         print(iter_d.__next__())
     except StopIteration:						        # 捕获错误StopIteration
         print('捕获到了错误,提醒!!')
         break									# 打印并退出
        
"""
异常有两大类:
	1.语法结构错误:需要当场修改 异常捕获没发完成
	2.逻辑错误:异常捕获可以处理
"""

for循环的内部原理

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


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

生成器

生成器:用户自定义的迭代器,本质就是迭代器
关键字:yield
def func():
     print('first')
     yield 666                       # 函数内如果有yield关键字,那么加括号执行函数的时候并不会触发函数体代码的运行
     print('second')
     yield 777			     # yield后面跟的值就是调用迭代器__next__你能得到的值
     print('third')
     yield 888			     # yield既可以返回一个值也可以返回多个值 并且多个值也是按照元组的形式返回
    
g = func()                           # 生成器初始化:将函数变成迭代器
print(g.__next__())                  # first 666
print(g.__next__())                  # second 777
有了yield关键字,我们就有了一种自定义迭代器的实现方式。yield可以用于返回值,但不同于return,函数一旦遇到return就结束了,而yield可以保存函数的运行状态挂起函数,用来返回多次值


# 自定义range功能
 for i in range(1,10,2):
     print(i)
 def my_range(start,end,step=1):
     while start < end:
         yield start
        start += step
        
        
# yield 传值
# 当函数体代码内有yield关键字时候,调用该函数不会执行函数体代码
 def dog(name):
     print('%s 准备开吃'%name)
     while True:
         food = yield
         print('%s 吃了 %s'%(name,food))
 g = dog('egon')
 g.__next__()         # 必须先将代码运行至yield,才能够为其传值
 g.send('包子')        # 给yield左边的变量传参  触发了__next__方法

# yield
    1. 帮你提供一种自定义生成器的方式 
    2. 保存函数上一次调用状态
    3. 可以返回值
    
# 与return之间的异同点
    相同:都可以返回值,并且都可以返回多个
    不同点:yield可以返回多次值,而return只能返回一次,函数立即结束
           yield还可以接受外部传入的值

生成器表达式

# 生成器表达式   
	生成器不会主动执行任何一行代码    
	必须通过__next__触发代码的运行
# 案例一:
res = [i for i in range(1,10) if i != 4]     
print(res)				               # [1, 2, 3, 5, 6, 7, 8, 9]

# 案例二:
res = (i for i in range(1,10) if i != 4)
 print(res)                                            # 与案例一不同,取出结果不会直接出现元组,而是生成器
 print(res.__next__())                                 # 取出老母猪,需要一个一个拍

# 案例三:
with open('xxx.txt','r',encoding='utf-8') as f:        # 将文本中的字符数相加
	g = (len(line) for line in f)
     print(sum(g))                                     # 相当于是将__next__的结果相加

常用内置方法

# print(abs(-11.11))              # 绝对值
# l = [0,1,2]
# print(all(l))                   # 传过来的元素全部是true就是true,只要有一个为false就返回false
# print(any(l))                   # 只要有一个true就返回true
# print(bin(10))                  # 十进制转二进制
# print(oct(10))                  # 十进制转八进制
# print(hex(10))                  # 十进制转十六进制
# print(int('1010',2))            # 二进制转十进制
# print(bool(1))                  # 布尔值:1为Ture
# print(bool(0))                  # 布尔值:0为false
# s = 'hello'
# print(s.encode('utf-8'))                # 转换成bytes
# print(bytes(s,encoding='utf-8'))        # 转换成bytes

# 可调用的(可以加括号执行相应功能的)
# l = [1,2,3]
# def index():
#     pass
# print(callable(l))                # False
# print(callable(index))            # True
# print(chr(122))                   # 将数字转换成ascii码表对应的字符
# print(ord('z'))                   # 将字符按照ascii表转成对应数字
# dir获取当前名称空间里面的名字
# l = [1,2,3]
# print(dir(l))                     # 打印对象中所有支持的名字

# enumerate 枚举
# l = ['a','b']
# for i,j in enumerate(l,1):
#     print(i,j)

s = """
print('hello baby~')
a = 1
b = 2
print(a + b)
"""
eval(s)                     # 可执行变量中的代码,但不支持逻辑代码
exec(s)                     # 支持逻辑代码

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

def name():
     username = '我是局部名称空间的username'
     print(locals())         				 # 查看局部名称空间的变量
name()

print(globals())           			         # 查看全局变量
def login():
     """
     一起嗨皮
     :return:
    """
print(help(login))            				 # 打印注释

n = 1
print(isinstance(n,int))        	 		 # 判断对象是否属于某个数据类型
print(pow(10,2))                     		         # 10的2次方
input().isalpha						 # 不是纯字母返回true,纯字母返回flase
posted @ 2021-01-22 09:47  元气少女郭德纲!!  阅读(100)  评论(0编辑  收藏  举报