首页 > 其他分享 >迭代器和生成器、异常捕获

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

时间:2023-12-05 21:55:05浏览次数:29  
标签:__ 迭代 res 捕获 生成器 next print

一、迭代器(Iterator)

1、可迭代对象(Iterable)和可索引对象

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

2、常见的可迭代对象

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

##  使用__iter__()创建可迭代对象
 
class MyIterable:
    # 构造函数
    def __init__(self, data):
        self.data = data
 
    def __iter__(self):
        return iter(self.data)
 
 
my_iterable = MyIterable([1, 2, 3])
for i in my_iterable:
    print(i)
 
 
##  使用__getitem__() 创建可索引对象
class MyIndexable:
    def __init__(self, data):
        self.data = data
 
    def __getitem__(self, index):
        return self.data[index]
 
my_indexable = MyIndexable([1, 2, 3])
print(my_indexable[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)

1、背景

  通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

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

2、创建的生成器

方式 1:元组的生成式就是生成器

G = (x * 2 for x in range(5))
print(G)
<generator object <genexpr> at 0x7fc528166c50>

方式 2:使用 yield  关键字

模拟range 的功能

复制代码
# range 可以传参,首先想到是函数
# 循环打印出指定范围的数字
def my_range(start, end=None, step=1):
    if not end:  # 如果 end 为空执行下面的代码
        end = start  # end=10
        start = 0  # start=0
    while start < end:  # 顾头不顾尾
        yield start   # 返回 start 的值
        start += step

print(my_range(10)) # <generator object my_range at 0x7fad80056c50>
print(list(my_range(1, 10, 2)))  # [1, 3, 5, 7, 9]
print(list(my_range(2, 10)))  # [2, 3, 4, 5, 6, 7, 8, 9]
print(list(my_range(10)))  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
复制代码

注意:由于 my_range()是生成器,数据只有在使用的时候才会打印出来,上面使用list 转数据类型调用,或者使用下面的 for  循环。

for i in my_range(10): # __next__
    print(i)

3、yield 传参

复制代码
def eat(name):
    print('%s正在干饭' % name)
    while True:
        food = yield
        print('%s正在吃%s' % (name, food))

# 函数里面只要有yield关键字,就不会执行函数,变成了生成器
res = eat('kevin')
res.__next__()  # 要求调用next()方法取值,yield  才能正常拿到send传的参数
res.send('馒头')
复制代码

4、生成器的特点:

  • 节约内存
  • 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的

5、__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是不管有没有异常都会走

引用案例

统计函数的执行次数,即每次运行,输出这是第几次调用函数

复制代码
def jilu(func):
    def inner(*args, **kwargs):
        global res
        try:
            with open(r'存储文件.txt', 'r', encoding='utf8') as f:
                res = int(f.read())
        except Exception as e:
            res = 0
        finally:
            res += 1
            res = str(res)
        with open(r'存储文件.txt', 'w', encoding='utf8') as f1:
            f1.write(res)
        res1 = func()
        return res1
    return inner

@jilu
def index():
    print('调用函数')

index()
print(res)
复制代码

刚开始文件没有内容,会报错

ValueError: invalid literal for int() with base 10: ''

 

一旦报错,except进行捕捉:res 赋值为 0

finally 无论怎么都执行,res +=1,将结果写入文件

第二次调用,文件有内容,不在报错。

finally 无论怎么都执行,在原有的基础上 res +=1,将结果写入文件

4、断言 assert

s = 1 + x

assert s == 2

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

5、raise 关键字

用于引发异常。它允许开发者显式地引发一个指定的异常,从而中断当前的代码执行流程,并将控制权传递给异常处理程序。

class Animal:
    # @abc.abstractmethod 不使用抽象方法实现强制子类有某个特性
    def speak(self):
        raise Exception("请先实现speak方法")
 
class People(Animal):
    # def speak(self):
    #     pass
    pass
 
"""主动抛出异常"""
stu = People()
stu.speak()
# 输出
#     raise Exception("请先实现speak方法")
# Exception: 请先实现speak方法

 

6、自定义异常信息

class MyException(BaseException):
    def __init__(self, msg):
        self.msg = msg
 
    def __str__(self):
        return self.msg
 
raise MyException("这是异常信息")

 

四、小练习

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
复制代码

 

标签:__,迭代,res,捕获,生成器,next,print
From: https://www.cnblogs.com/Jessica-Jmm/p/17878383.html

相关文章

  • python 可迭代对象 迭代器 生成器
    一个对象若要用for循环则需实现def__iter__(self,item)或def__iter__(self,item)方法可迭代对象实现了def__iter__(self,item)方法  迭代器  实现了def__iter__(self,item)和def__next__(self)方法  迭代器一定是可迭代对象可迭代对象不一定是迭代器from......
  • Unity DOTS系列之System中如何使用SystemAPI.Query迭代数据
    最近DOTS发布了正式的版本,我们来分享一下System中如何基于SystemAPI.Query来迭代World中的数据,方便大家上手学习掌握UnityDOTS开发。SystemAPI.Query的使用System有两种,一种是Unmanaged的ISystem,一种是managed的SystemBase,这两种System都可以通过SystemAPI.Query来迭代与......
  • 如何开发代码生成器平台?分享下思路
    大家好,我是鱼皮,我的新项目《鱼籽-定制化代码生成项目》系列教程正式开始!本次项目依然是从0到1带大家开发,会遵循企业项目开发的标准流程:需求分析=>技术选型=>项目设计=>项目初始化=>Demo编写=>前后端开发实现=>测试验证=>部署上线,带大家一步步完成整个项目。......
  • 全局异常捕获
    DispatcherUnhandledException——UI线程未被处理的异常捕获从App对象中订阅DispatcherUnhandledException事件publicpartialclassApp:Application{publicApp(){//DispatcherUI线程未被处理的异常this.Disp......
  • java 捕获异常Exception 获取异常信息的方法 e.toString() e.getMessage() e.printSta
    Java异常中e.getMessage()和e.toString()e.printStackTrace()的区别e.getMessage():打印异常的原因e.toString():打印异常类型和异常的原因e.printStackTrace():打印完整的异常堆栈信息  总结e.getMessage()和e.toString()方法:打印的异常信息太少,没有具体......
  • 新建模块&新建用户表&修改代码生成器文件&新建菜单
    1.新建模块打开IDEA在项目结构中新建rome-hotel的一个springboot项目,什么依赖都不需要 在pom.xml文件中修改坐标,引用父坐标 在父级pom文件中将模块加入 在rome-admin中的pom文件中加入admin-hotel,这样就能带动这个模块启动 将包名修改成和rome-admin一样 再创建其......
  • “数据结构”模式之迭代器(Iterator)模式
    常常有一些组件在内部具有特定的数据结构,如果让客户程序依赖这些特定的数据结构,将极大地破坏组件的复用。这时候,将这些特定数据结构封装在内部,在外部提供统一的接口,来实现与特定数据结构无关的访问,是一种行之有效的解决方案。典型模式:CompositeIteratorChainofResposibilit......
  • stl中迭代器的删除
    Z1584.noip题海战Description某校举行了k场集训,集训有两种方式:比赛和训练对于每场比赛,他要保证所出的所有试题,对于所有学生来说,都是从来没有做过的而对于每场训练,他要保证所出的所有题都被每一个参赛学生做过。FormatInput第一行2个正整数n和m,表示学生数和试题总数第2~n+1行......
  • python 解压可迭代对象赋值给多个变量
    1.2解压可迭代对象赋值给多个变量问题如果一个可迭代对象的元素个数超过变量个数时,会抛出一个ValueError。那么怎样才能从这个可迭代对象中解压出N个元素出来?解决方案Python的星号表达式可以用来解决这个问题。比如,你在学习一门课程,在学期末的时候,你想统计下家庭作业......
  • java: 未报告的异常错误java.io.UnsupportedEncodingException; 必须对其进行捕获或声
    原问题代码:/**MD5编码相关的类@authorwangjingtao*/publicclassMD5{//首先初始化一个字符数组,用来存放每个16进制字符privatestaticfinalchar[]hexDigits={'0','1','2','3','4','5','6','7'......