迭代器和生成器、异常捕获

君自故乡来,应知故乡事 / 2023-06-02 / 原文

一、迭代器(Iterator)

1、可迭代对象(Iterable)

存储了元素的一个容器对象,且容器中的元素可以通过“__iter__( )”方法或“__getitem__( )”方法访问。可迭代对象不能独立进行迭代,可通过“for…in”遍历来完成

2、常见的可迭代对象

字符串、列表、元组、字典、集合、文件

3、迭代器对象

可迭代对象调用__iter__( )方法成为迭代器对象,迭代器对象是可以记住遍历的位置的对象。

4、迭代器特性

  • 迭代器对象可以使用iter()函数来创建。

  • 迭代器对象可以使用next()函数来访问容器中的元素。

  • 当迭代器对象遍历完容器中的元素时,它将引发StopIteration异常。

  • 可以使用for循环来遍历迭代器对象,因为for循环自动处理了StopIteration异常。

  • 迭代器对象在遍历过程中只能向前移动,不能后退或重置。

  • 迭代器对象可以被多个迭代器同时使用,每个迭代器都会维护自己的迭代状态。

  • 生成器对象是一种特殊的迭代器,它们可以使用yield语句来定义。

  • 迭代器对象可以用于惰性计算,即只有在需要时才计算下一个元素,从而节省内存和计算资源。

  • 迭代器其实是一种不依赖于索引取值的方式!

5、易混淆

ll = [1, 2, 3, 4]

# StopIteration 当数据被取值完的时候,如果在次next会直接报错
res = ll.__iter__()
print(res.__next__())
print(res.__next__())
print(res.__next__())
print(res.__next__())
print(res.__next__())  

# 取出来的值都是 1,因为每次打印都调用的ll.__iter__方法,数据被重置
print(ll.__iter__().__next__()) # 1
print(ll.__iter__().__next__()) # 1
print(ll.__iter__().__next__()) # 1
print(ll.__iter__().__next__()) # 1

 

 

 

 

 

二、生成器(generator)

 

理解生成器,最好的方法就是给他取个突出其本质的别名:生成数据的机器代码。

        生成器是一种用时间换空间的做法。比如,利用list列表储存全体正整数,无穷个正整数再大的内存也无法装得下,这个时候就可以使用生成器,实现用一段代码来储存全部正整数的作用。如下面代码,每隔0.5秒自动递增生成一个正整数。

 

 

4,__next__()&next()和send()方法

1、__next__()&next()的区别

        __next__()是生成器对象的实例方法,next()是python的内置方法。他们实现的功能是一样的,只能对可迭代的对象使用。

2、next()和send()用以唤醒生成器

        当生成器函数中执行yield时,程序会卡在yield的地方不执行,next()和send()的作用就是唤醒卡住的程序,让他继续执行。

3、send()方法的作用

        send()作为生成器对象的实例方法,可以向生成器发送数据并唤醒生成器函数。一般send()方法要写在next()方法后面,当next()和send()写在一块时,相当于唤醒两次生成器。

 

三、异常捕获

1、代码不能正常运行的时候,编辑器会曝出错误提示,包含错误追踪、错误类型和错误详细信息

2、python  常见的错误类型

  1. 语法错误(SyntaxError):代码中存在语法错误,如拼写错误、缺少括号、缩进错误等。
  2. 名称错误(NameError):使用了未定义的变量或函数名。
  3. 类型错误(TypeError):使用了错误的数据类型或数据类型不匹配,如将字符串和数字相加。
  4. 索引错误(IndexError):使用了不存在的索引或切片。
  5. 键错误(KeyError):使用了不存在的字典键。
  6. 属性错误(AttributeError):尝试访问不存在的对象属性或方法。
  7. 文件不存在错误(FileNotFoundError):尝试打开不存在的文件时引发的错误。
  8. 除以零错误(ZeroDivisionError):尝试除以零时引发的错误。
  9. 异常错误(Exception):在代码中使用了未处理的异常。
  10. 导入错误(ImportError):尝试导入不存在的模块或函数。
  11. 内存错误(MemoryError):尝试使用过多的内存时引发的错误。

3、解决异常

语法结构

except 可以写多种错误类型

try
    # 被监测的代码: 一般是可能会发生的错误
except 错误类型1 as e
    print(e)
except 错误类型2 as e
    print(e)
except 错误类型3 as e
    print(e)
except 错误类型4 as e
    print(e)

万能的捕获结构(关键字 Exception

try

except Exception as e

由于错误类型太多,没法全部列出,使用Exception关键字可以捕获任意类型的错误

try:
    # print(name)
    # 1/0
    # l = [1,2,3]
    # print(l[6])
    # 1/0
    d = {'a':1}
    print(d['aaa'])
except NameError as e:
    print(e) # name 'name' is not defined
except IndexError as e:
    print(e) # name 'name' is not defined
except Exception as e:
    print(e)
else:
    print('看一下else什么时候走的?')
finally:
    print('看一下finally什么时候走?')
"""
    没有异常的时候else会走,有异常的时候else不会走
    finally是不管有没有异常都会走
"""

4、断言 assert

s = 1 + x

assert s == 2

assert 条件 条件必须成立,如果不成立,代码在这一行直接中断

四、小练习

1、不使用 for  循环取出 l  的元素

l = [1, 2, 3, 4, 5, 6, 7]
l1 = l.__iter__()
count = 0
while count <= len(l):
    try:
        print(next(l1))
        count += 1
    except Exception:
        break