查看: 54|回复: 0

[转载图文] Python 异常处理与反射机制

[复制链接]
发表于 2020-5-26 13:23:56 | 显示全部楼层 |阅读模式
Python 异常处理  软件异常(Exception),是指当程序出现错误后程序的处理方法,异常机制提供了程序正常退出的安全通道.当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器,如序列的下标越界、打开不存在的文件、空引用异常等,当异常被引发时,如果没有代码处理该异常,异常将被 Python 接收处理,当异常发生时 Python 解释器将输出一些相关的信息井终止程序的运行,以确保程序不会出现终止执行的情况.
  异常时任何语言必不可少的一部分,Python 提供了强大的异常处理机制,通过捕获异常可以提高程序的健壮性,异常处理还具有释放对象,终止循环的运行作用,在Python中,BaseException 是所有异常类的基类,所有的内置异常都是它的派生类, Exception 是除了 SystemExit,GeneratorExit 和 KeyboardInterrupt 之外的所有内置异常的基类,用户自定义的异常也应该继承它,它包括以下异常:
异常类型关于语句的解释说明
AttributeError试图访问一个对象没有的树形
FileNotFoundError输入/输出异常,无法打开的文件
ImportError无法引入模块或包,路径文件错误
IndentationError语法错误(的子类),代码没有对齐
IndexError数组下标索引超出序列边界
KeyError试图访问字典里不存在的键
Exception万能错误拦截,可以断下所有错误
KeyboardInterruptCtrl+C被按下,触发此类异常
NameError使用一个还未被赋予对象的变量
SyntaxErrorPython代码非法,代码不能编译
TypeError传入对象类型与要求的不符合
UnboundLocalError试图访问还未被设置的局部变量
ValueError传入调用者不期望的值  Python 语言内的异常使用继承结构创建,这种设计方式非常灵活,可以在异常处理程序中捕捉基类异常,也可以捕捉各种子类异常,Python中使用try...except语句捕捉异常,异常类型定义在try子句的后面,如果在except子句后面将异常类型设置为Exception,那么异常处理程序将捕获除了中断外的所有异常,因为Exception类是其他异常类的基类.
◆try..except◆  try..except 语句用于处理问题语句,捕获可能出现的异常. try 子句中的代码块放置可能出现异常的语句,except 子句中的代码块处理异常.当异常出现时,Python会自动生成1个异常对象,该对象包括异常的具体信息,以及异常的种类和错误位置.
  例如当以下代码执行的时候,我们给其指定一个不存在的文件名,那么他就会报一个FileNotFoundError的异常.
import os
import sys

open("test.txt","r")

Traceback (most recent call last):
  File "C:\Users\LyShark\Desktop\my.py", line 5, in <module>
    open("test.txt","r")
FileNotFoundError: [Errno 2] No such file or directory: 'test.txt'
  由于test.txt文件不存在,程序出现了例外,解释器提示FileNotFoundError异常,为了使程序更加友好,我们可以添加以下代码,来捕捉这个异常,并将其跳过,这样一来我们再次运行代码,会发现程序出现了这个文件不存在了.的提示,说明异常被捕捉到了.
import os
import sys

try:
    open("test.txt","r")
except FileNotFoundError:
    print("这个文件不存在了.")
except:
    print("程序出现了其他异常.")
  当然了try..except语句还可以添加一个else子句,当try子句中的代码发生异常时,程序直接跳转到except子句里去执行,反之程序将执行else语句的内容,如下示范,执行除法运算时当除数为0,则抛出ZeroDivisionError异常,as temp的意思是将出现的错误保存到temp变量中.
import os
import sys

try:
    result = 10/0
except ZeroDivisionError as temp:
    print("0不能被整除",temp)
else:
    print(result)
  除了上面的路子可以走以外,异常处理语句也可以嵌套起来,只是调用的时候也会遵循相应的调用原则,以下语句如果外层try子句中的代码块引发异常,程序将直接跳转到外层try对应的except子句,而内部的try子句将不会被执行.
import os
import sys

try:
    s="lyshark"
    try:
        print(s[0] + s[1])
        print(s[0] - s[1])
    except TypeError:
        print("字符串不支持减法运算")
except:
    print("外部的异常..")
  实例1: 编写一个简单的异常处理语句.
import os
import sys

temp=["lyshark","admin"]

try:
    temp[20]
except IndexError as e:
    print("索引出现错误,错误代码:",e)
  实例2: 写程序时需要考虑到try代码块中可能出现的任意异常,建议这样来写.
import os
import sys

string="lyshark"

try:
    int(string)
except IndexError as e:
    print("索引错误:",e)
except KeyError as e:
    print("键值错误:",e)
except ValueError as e:
    print("数值错误:",e)
  实例3: 写异常处理程序,在一个异常语句中处理多个异常,不推荐的写法.
import os
import sys

string="lyshark"

try:
    int(string)
except (IndexError,KeyError,ValueError) as e:
    print("错误:",e)
  实例5: 万能的异常处理语句,Exception语句,它可以处理除了系统中断以外的任意异常.
import os
import sys

string="lyshark"
array=["admin","lyshark"]

try:
    int(string)
    array[2]
except Exception as e:
    print("异常数据:",e)
  实例6: 使用else语句,当一切执行正常以后,执行这个操作.
import os
import sys

array=["admin","lyshark"]

try:
    array[0]
except Exception as e:
    print("异常数据:",e)
else:
    print("一切执行正常,没有出现错误..")
◆try..finally◆  try..finally语句与else语句差不多,但finally语句是无论异常是否发生了,finally子句里面的内容都会被执行,所有finally语句通常都用于关闭因异常而不能释放的系统资源,如下定义的例子.
import os
import sys

try:
    open("test.txt","r")
except Exception:
    print("异常了..")
finally:
    print("结束执行我..")

异常了..
结束执行我..
  当程序出现错误时,Python会自动引发异常,也可以通过raise语句显示的引发异常,这里我们来看一个异常主动触发的语句,raise语句,此语句用于主动的触发异常.
import os
import sys

try:
    raise Exception("错误了..")
except Exception as e:
    print("异常了..",e)
◆自定义异常◆  Python 允许程序员自定义异常类型,用于描述 Python 异常体系中没有涉及的异常情况,自定义异常必须继承ExcePtion 类.自定义异常按照命名规范以 Error 结尾,显式的告诉程序员该类是异常类,自定义异常使用 raise 语句引发,而且只能通过手工方式触发,下面这段代码演示了自定义异常的使用.
import os
import sys

class lysharkException(Exception):
    def __init__(self,msg):
        self.message = msg

    def __str__(self):
        return self.message
        #return "错误了.."

try:
    raise lysharkException("我的异常")
except lysharkException as e:
    print("输出内容:",e)

输出内容: 我的异常
  好了,以上就是关于异常处理的常用语法和内容了,这里只是个人笔记,如需更加细致的了解,自行看书本吧.


Python 反射机制  在程序开发中,常常会遇到这样的需求:在执行对象中的某个方法,或者在调用对象的某个变量,但是由于一些原因,我们无法确定或者并不知道该方法或者变量是否存在,这时我们需要一个特殊的方法或者机制来访问或操作该未知的方法或变量,这种机制就被称之为反射.
  反射机制:反射就是通过字符串的形式,导入模块.通过字符串的形式,去模块中寻找指定函数,对其进行操作,也就是利用字符串的形式去对象(模块)中操作成员,一种基于字符串的事件驱动,这种机制就叫做反射机制.
  Python 中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,这四个函数分别用于在对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员、导入模块以字符串方式导入,接下来我们将具体介绍它们的应用场景.
  hasattr: 检查指定类中是否有指定成员,也就是检查是否含有指定成员函数.
import os
import sys

class dog(object):
def __init__(self,name):
self.name=name

def eat(self):
print("%s 在吃东西..."%self.name)

d = dog("dogging")
choice = input("输入数据:").strip()

# (d=类的实例名称) (choice=数据保存位置)
print(hasattr(d,choice))

#--输出结果-----------------------------------
输入数据:eat
True
  getattr: 获取指定类中是否有指定的成员,结果打印出1个字符串,映射出函数所在内存地址.
import os
import sys

class dog(object):
def __init__(self,name):
self.name=name

def eat(self):
print("%s 在吃东西...",self.names)

d= dog("dogging")
choice = input("输入数据:").strip()

# (d=类的实例名称) (choice=数据保存位置)
print(getattr(d,choice))

# 同样的,在getattr后面加上括号,则可调用指定方法.
getattr(d,choice)()

#--输出结果-----------------------------------
输入数据:eat
<bound method dog.eat of <__main__.dog object at 0x000001D71FD47128>>
dogging 在吃东西..
  getattr: getattr一般的通用写法,映射出函数所在内存地址后,给函数传递参数.
import os
import sys

class dog(object):
def __init__(self,name):
self.name=name

def eat(self,food):
print("%s 在吃东西..."%self.name,food)

d= dog("dogging")
choice=input("输入数据:").strip()

func=getattr(d,choice)
func("调用传递参数..")
#--输出结果-----------------------------------
输入数据:eat
dogging 在吃东西... 调用传递参数..
  setattr: 动态装配函数,在外部创建函数,然后将外部函数,动态的装配到指定类的内部.
import os
import sys

def bulk(self):                               #定义一个外部函数.
print("%s 在大叫..."%self.name)

class dog(object):
def __init__(self,name):
self.name=name

def eat(self,food):
print("%s 在吃东西..."%self.name,food)


d= dog("dogging")
choice=input("输入数据:").strip()           #传递字符串
setattr(d,choice,bulk)                     #将bulk()外部方法,动态添加到dog类中.
d.bulk(d)                                  #调用bulk()方法,这里要将d自己传递进去.
#--输出结果-----------------------------------
输入数据:bulk                              #调用成功,说明装配成功啦.
dogging 在大叫...
  setattr: 动态装配属性,在外部动态装配属性,并设置默认初始值为22.
import os
import sys

def bulk(self):
print("%s 在大叫..."%self.name)

class dog(object):
def __init__(self,name):
self.name=name

def eat(self,food):
print("%s 在吃东西..."%self.name,food)

d= dog("dogging")
choice=input("输入装配变量:").strip()    #输入装配变量名

setattr(d,choice,22)                    #设置初始值为22
print(getattr(d,choice))                #打印装配的变量值

#--输出结果-----------------------------------
输入装配变量:temp
22
  delattr: 动态删除函数,以下演示动态的删除dog类中的,eat这个函数,后期再次调用会发现不存在了.
import os
import sys

class dog(object):
def __init__(self,name):
self.name=name

def eat(self):
print("%s 在吃东西..."%self.name)

d= dog("dogging")
choice=input("输入内容:").strip()       #输入要删除的方法名

delattr(d,choice,eat)                  #通过此方法,删除eat函数
d.eat()                                #再次调用会错误,已经动态删除了

#--输出结果-----------------------------------
输入内容:eat
Traceback (most recent call last):
  File "test.py", line 15, in <module>
    delattr(d,choice,eat)
NameError: name 'eat' is not defined


温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的最好奖励,还可以获得学币奖励,请尊重作者的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046
微信公众号
快速回复 返回顶部 返回列表