zoukankan      html  css  js  c++  java
  • 异常处理、迭代器、推导式、生成器

    异常处理:
     导致程序运行过程中出现异常中断和退出的错误,我们称之为异常。
     为了保证程序的正常运行,提高程序的健壮性和可用性。我们应当尽量考虑全面。将可能出现的异常进行处理
     python处理异常的机制:
     基本语法:

    # try:
    # pass # 程序代码
    # except Exception:
    # pass # 程序异常使执行的代码
    # try:
    # print('123')
    # a = 1/0
    # except Exception as e:
    # print(e)
    # print('after except!')
    
    # 运行结果:
    # 123
    # division by zero
    # after except!
    
    # 当程序发生的异常不在捕获列表中时,依然会抛出异常
    # try:
    # a = 1/0
    # except IndexError as e: # IndexError 表示下标索引错误
    # print(e)
    # 运行结果报错:ZeroDivisionError: division by zero

    try......except

     在python的异常中,有一个通用异常:Exception,它可以捕获任意异常

     1)很多时候程序只会弹出那么几个异常,没有必要针对所有异常进行捕获,那样的效率会很低

     2)根据不同的异常种类,制定不同的处理措施,用于准确判断错误的类型,存储错误日志

    (1)函数嵌套处理异常

    # def f1():
    #     a = 1/0
    # def f2():
    #     print('f2')
    #     f1()
    # def f3():
    #     print('f3')
    #     f2()
    # try:
    #     f3()
    # except Exception as e:
    #     print(e)
    
    # 运行结果:
    # f3
    # f2
    # division by zero

    (2)try.....except的嵌套

    # 如果一个异常没有与任何的except匹配,那么这个异常将会传递给上层的try中,直到程序最顶端如果还没有被捕获,那么将弹出异常

    # try:
    #     try:
    #         a = 1/0
    #     except IndexError as e1:
    #         print('this is e1:',e1)
    # except ZeroDivisionError as e2:
    #     print('this is e2:',e2)
    
    # 运行结果:this is e2 division by zero

    (3)使用一个try跟多个except(推荐使用)

    1 # try:
    2 #     a = 1/0
    3 # except IndexError as e1:
    4 #     print('this is e1:',e1)
    5 # except ZeroDivisionError as e2:
    6 #     print('this is e2:',e2)

    7 # 运行结果:this is e2: division by zero

    # (4)或者except后面跟一个元组,元组中包含多个异常类,有点像Exception的特殊形式

    1 # try:
    2 #     a = 1/0
    3 # except (IndexError,ZeroDivisionError):
    4 #     print('error')

    try...except...finally(else)...

    # finally和else子句:

    # else子句必须放在所有的except子句之后,会在try子句没有发生异常的时候执行

    # finally子句无论try和except情况如何finally子都会执行

    1 # try:
    2 #     a = 1/0
    3 # except ZeroDivisionError as e:
    4 #     print('error')
    5 # else:
    6 #     print('else')
    7 # finally:
    8 #     print('finally')

    raise:主动抛出异常

    # 主动抛出异常:raise

    # python内置了一个关键字raise,可以主动触发异常,作为警告或者特殊处理

    # 使用raise抛出自定义的异常

    # 例题:用户录入自己的性别:1表示男 2表示女
    
    # class MyError(Exception):
    #     def __init__(self,msg):
    #         self.msg = msg
    #     def __str__(self):
    #         return self.msg
    
    # sex = input('enter your sex:')
    # if sex!='1' and sex!='2':
    #     raise MyError('您输入的性别有误!')
    # else:
    #     print('right!')
    
    # 运行结果:报错终止程序
    # raise MyError('您输入的性别有误!')
    # __main__.MyError: 您输入的性别有误!

    自定义异常

    # 自定义异常应该继承Exception类,直接继承或间接继承都可以

    # class MyErr(Exception):
    #     def __init__(self,msg):
    #         self.msg = msg
    #     def __str__(self):
    #         return self.msg
    
    # err = MyErr('find error range')
    # print(err)  # find error range

    迭代器

    # 迭代:通过for循环遍历"对象"的每一个过程,这里的对象指的就是可迭代对象。for循环遍历的只能是可迭代的对象

    # 可迭代对象:list/tuple/string/dict/set/bytes/文件都是可迭代的数据类型/可迭代对象

    # 如何判断一个对象是否为可迭代对象:可以通过collections模块作用在isinstance中来判断对象是否可迭代

    # from collections import Iterable  # Iterable迭代类型
    # from collections.abc import Iterable
    # class Test():
    #     pass
    # alist = [1,2,3]
    # str = 'abc'
    # t = Test()
    # print(isinstance(alist,Iterable))  # True
    
    # print(isinstance(str,Iterable))     # True
    
    # print(isinstance(t,Iterable))       # False

    python提供了不依赖于索引取值的方式就是迭代器迭代取值

    # 迭代器是一种可以被遍历的对象,并且能作用于next()函数

    # 性质:迭代器对象从集合的第一个元素开始访问,直到所有元素被访问完结束。

    # 迭代器只能往后遍历不能回溯,不像列表可以根据搜索引取值

    迭代器作用:节省内存

    iter()和next()

    # 迭代器通常要实现两个基本方法:iter()/.__iter__()和next()/.__next__()

    # 注:1、可迭代对象并不一定是迭代器

    #     2、常见的数据结构,字符串、列表、元组都属于可迭代对象,并不是迭代器

    # 可以使用type()查看列表和迭代器类型的不同:

    # 使用python内置的iter()方法创建迭代器对象

    # from collections.abc import Iterable

    # alist = [1,2,3]

    # print(type(alist))   # <class 'list'>

    调用可迭代对象的下的__iter__方法会将其装换成迭代器,当进行迭代时才会调用iter方法

    # # 将列表转换成迭代器

    # iter_alist = iter(alist)

    # print(type(iter_alist))   # <class 'list_iterator'>

    # 使用next()方法获取迭代器的下一个元素

    from  collections.abc import Iterable
    alist = [1,2,3]
    iter_alist = iter(alist)
    # print(next(iter_alist))
    # print(next(iter_alist))
    # print(next(iter_alist))
    
    # 运行结果:
    # 1
    # 2
    # 3

     使用for循环遍历迭代器:

    # for i in iter_alist:
    #     print(i)
    
    d = {"a":1,"b":2,"c":3}
    for k in d:
        print(k)

    for循环的工作原理:(也可称之为迭代器循环)

    1、d.__iter__()得到一个迭代器对象

    2、迭代器对象.__next__()拿到一个返回值,然后该返回值赋给k

    3、循环往复步骤2,直到抛出StopInteration异常,for循环会捕捉异常结束循环

    总结:

    # 可迭代对象的优缺点:

    # 优点:可以直观查看里面的对象,如直接查看列表的内容

    # 缺点:全部内容要加载至内存中,故占用内存

    # 迭代器的优缺点:

    # 优点:提供了一种通用不依赖索引的迭代取值方式;

    # 节省内存,迭代器在内存中相当于只占一个数据的空间:因为每次取值上一条数据会在内存释放,加载当前的此条数据。

    # 缺点:因为有next()方法,即只能往后取值,不能往前,取值不能取指定的某一个值;无法预测迭代器的长度

    # 总结:迭代器和可迭代的区别

    可迭代对象 Iterable  迭代器Iterator

    # 1、凡是可作用于for循环的对象都是可迭代类型

    # 2、凡是可作用于next()函数的对象都是迭代器对象

    # 3、list、dict、str等是可迭代对象但不是迭代器,因为next()函数无法调用他们

    # 可以通过iter()函数将它们转换成迭代器

     自定义迭代器

    # 为了让我们自己写的类成为一个迭代器,需要在类里实现__iter__()和__next__()方法

    # 实际上在使用next()函数的时候,调用的就是迭代器对象__next__方法

    # python要求迭代器本身也是可迭代的,

    # 所以我们还要为迭代器实现__iter__方法,而__iter__方法要返回一个迭代器

    # 迭代器自身正是一个迭代器,所以迭代器的__iter__方法返回自身即可

    # 例题:#迭代生成指定范围数列的平方值
    
    # class IterObj():
    #     def __init__(self,start,end):
    #         self.start = start
    #         self.end = end
    #         self.index = 1
    
    #     def __iter__(self):
    #         print('iter')
    #         return self
    
    #     def __next__(self):
    #         if self.index > self.end:
    #             raise StopIteration
    #         res = self.index **2
    #         self.index +=1
    #         print('next')
    #         return res
    
    # i = IterObj(1,5)
    # print(type(i))
    # for j in i:
    #     print(j)

    # 斐波那切数列实现

    # class IterObj():
    #     def __init__(self,count):
    #         self.count = count
    #         self.index = 0 # 记录生成第几个元素
    #
    #         self.num1 = 0
    #         self.num2 = 1
    #         self.num3 = 1
    #     def __iter__(self):
    #         return self
    
    #     def __next__(self):
    #         if self.index > self.count:
    #             raise StopIteration
    #         value = self.num1
    #         self.index += 1
    #         self.num1,self.num2,self.num3 = self.num2,self.num3,self.num2+self.num3
    #         return value
    
    # obj = IterObj(10)
    # for i in obj:
    #     print(i)

    # 实现类似iter功能的类:可以使得将列表转换成迭代器

    # class IterObj():
    #     def __init__(self,alist):
    #         self.alist = alist
    #         self.index = 0
    
    #     def __iter__(self):
    #         return self
    
    #     def __next__(self):
    #         if self.index >= len(alist):
    #             raise StopIteration
    #         value = alist[self.index]
    #         self.index += 1
    #         return value
    
    # obj = IterObj([1,2,3])
    # for i in obj:
    #     print(i)

    推导式

     (1)列表推导式:

    语法:[表达式 for item in 可迭代对象 if 条件] 返回结果为列表

    lst = [x*2 for x in range(1,10)]

    # 增加条件语句:alist = [x*x for x in range(1,11) if x%2==0]  

    # 多重循环:

    # 同时循环a和b两个变量:re = [a+b for a in '123' for b in 'abc']

     (2)字典推到式

    语法:{键:值 for k in 可迭代对象 if 条件}

    字典推导式 {k:v for k,v in dic.items()}

    # dic = {x:x**2 for x in (2,4,6)}  # x:x**2指字典的key:value

    例1 将一个字典的键值对倒换

    dic = {"id":1001,"name":"yuan","age":22,"weight":"70kg"}

    new_dic={v:k for k,v in dic.items()}

    # {1001: 'id', 'yuan': 'name', 22: 'age', '70kg': 'weight'}

    例2:将一个字典的键转换成大写

    new_dic={k.upper():v for}

    new_dic={k.upper():v for k,v in dic.items()}

    print(new_dic)

    # {'ID': 1001, 'NAME': 'yuan', 'AGE': 22, 'WEIGHT': '70kg'}

    例3:保留name与age的键值对

    new_dic={k:v for k,v in dic.items() if k=='name' or k=='age'}

    print(new_dic) # {'name': 'yuan', 'age': 22}

     (3)集合推导式

    # a = {x for x in 'sfgfgh'}

     (4)元组推导式

    # tup = (x for x in range(9))  # 是一个生成器

    # print(tup)  # <generator object <genexpr> at 0x000001F55F9955F0>

    # tup = tuple(x for x in range(9))

    # print(tup)  # (0, 1, 2, 3, 4, 5, 6, 7, 8)

    生成器

    数据序列或集合内的元素的个数非常巨大,如果全造出来并放入内存,对计算机的压力非常大 如果元素可以按照某种算法推算出来,需要该元素的话那就计算到哪个元素,那么就可以在循环的过程中不断推算出后续的元素,而不必创建完整的元素集合,从而节省大量的空间。在Python中,这种一边循环一边计算出元素的机制,称为生成器:generator。 **生成器是一种特殊的迭代器,生成器自动实现了”迭代器协议“(即iter方法和next方法)**,生成器就是自定义的迭代器

    创建生成器 创建生成器的两种方式:

    1)生成器推导式:

    tup = (x for x in range(3))
    # 可以通过next()函数获得generator的下一个返回值
    next(tup)
    print(type(tup)) # <class 'generator'>
    
    # 通常情况下,使用for循环遍历生成器
    for i in tup:
        print(i)

    2)yield关键字创建生成器

    在 Python中,使用yield返回的函数会变成一个生成器(generator)。 在调用生成器的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行next()方法时从当前位置继续运行。下面重点理解yield关键字的使用:

    *yield 是一个类似 return 的关键字,只是这个函数返回的是个生成器

    *当你调用这个函数的时候,函数内部的代码并不立马执行 ,这个函数只是返回一个生成器对象

    *当你使用for进行遍历的时候或者调用next函数后,函数中的代码才会执行

    def mySum():
        print('before')
        print('after')
        yield 'result'
    
    f = mySum()
    print(type(f),next(f))
    # 运行结果:
    # before
    # after
    # <class 'generator'> result

    思考:下述函数的执行结果是什么?

    def yieldTest():
        i = 0
        while i < 3:
          temp = yield i 
          print(temp)
          i += 1
    
    obj = yieldTest() # 返回的生成器对象
    print(next(obj))
    print(next(obj))
    运行结果:
    0   # yield i 停止
    None  # 将None赋值给temp
    1    # i+1 = 1 yield i 停止
    
    next()会触发函数体代码的运行,然后遇到yield停下来,将yield后的值当作本次调用的结果返回
    
    for i in yieldTest():  # 就是迭代器
        print(i)
    运行结果:
    0
    None
    1
    None
    2
    None

    总结yield:

    有了yield关键字,我们就有了一种自定义迭代器的实现方式,yield可以用于返回值,但不同于return,函数一遇到return就结束了,而yield可以保存函数的运行状态挂起函数用来返回多次值

  • 相关阅读:
    uninstall_edge:win10带浏览器edge卸载工具
    安装spacedesk后,Win10状态栏图标间距变宽
    jacob实现语音朗读一段文本
    汇编语言-12内中断
    告警只提示一次,未解决也不再次提示
    汇编语言-11标志寄存器
    第2章 顺序表及其顺序存储
    第1章 概论
    再见:计算机行业
    QPainter
  • 原文地址:https://www.cnblogs.com/python-htl/p/15251716.html
Copyright © 2011-2022 走看看