设为首页 收藏本站
查看: 641|回复: 0

[经验分享] Python3 错误和异常

[复制链接]
YunVN网友  发表于 2018-8-10 09:43:14 |阅读模式
  Edit
  笔记内容:Python3 错误和异常
  笔记日期:2017-11-12
Python3 错误和异常

  •   语法错误
  •   异常
  •   异常处理
  •   抛出异常
  •   用户自定义异常
  •   finally语句
  •   预定义的清理行为
  异常处理机制概述:
  异常处理,是编程语言或计算机硬件里的一种机制,用于处理软件或信息系统中出现的异常状况(即超出程序正常执行流程的某些特殊条件)。通过异常处理,我们可以对用户在程序中的非法输入进行控制和提示,以防程序崩溃。
  就好比一个旅游景点,每到一个有可能出现问题情况的地方就会设置一个处理问题的处理点,不同的问题有不同的处理点,例如花粉过敏有花粉过敏的处理点,摔伤有摔伤的处理点等。程序也是如此会出现各种各样的错误,同理不同的异常错误有不同的异常错误处理方法。
  各种编程语言在处理异常方面具有非常显著的不同点(错误检测与异常处理区别在于:错误检测是在正常的程序流中,处理不可预见问题的代码,例如一个调用操作未能成功结束)。某些编程语言有这样的函数:当输入存在非法数据时不能被安全地调用,或者返回值不能与异常进行有效的区别。例如,C语言中的atoi函数(ASCII串到整数的转换)在输入非法时可以返回0。在这种情况下编程者需要另外进行错误检测(可能通过某些辅助全局变量如C的errno),或进行输入检验(如通过正则表达式),或者共同使用这两种方法。
  在python中我们可以通过try-except语句来捕捉异常,语法错误的话开发工具都会有提示的。
语法错误
  语法错误或者称之为解析错误,是初学者经常碰到的,如下实例:
>>> while True print('Hello world')  
  File "<stdin>", line 1, in ?
  
    while True print('Hello world')
  
                   ^
  
SyntaxError: invalid syntax
  这个例子中,函数 print() 被检查到有错误,是它前面缺少了一个冒号( : )。
  解释器会指出了出错的一行,并且在最先找到的错误的位置标记了一个小小的箭头。
异常
  即便代码的语法是正确的,但是在运行它的时候,也有可能发生错误。运行期间检测到的错误被称为异常,例如不能被0整除错误,或者空指针异常。
  大多数的异常都不会被程序处理,都以错误信息的形式展现在这里:
>>> 10 * (1/0)   # 不能被0整除异常  
Traceback (most recent call last):
  
  File "<stdin>", line 1, in ?
  
ZeroDivisionError: division by zero
  
>>> 4 + spam*3
  
Traceback (most recent call last):
  
  File "<stdin>", line 1, in ?
  
NameError: name 'spam' is not defined   # 变量未声明异常
  
>>> '2' + 2  # 类型异常
  
Traceback (most recent call last):
  
  File "<stdin>", line 1, in ?
  
TypeError: Can't convert 'int' object to str implicitly
  异常会有不同的类型,这些类型都作为信息的一部分打印出来,以上例子中的类型有ZeroDivisionError(不能被0整除异常),NameError( 变量未声明异常) 和
TypeError(类型异常),这些异常类型能提示开发人员发生的是什么样的异常,这样就可以分析错误发生在何处。
  错误信息的前面部分显示了异常发生的上下文,并以调用栈的形式显示具体信息。
异常处理
  在python中通过try-except语句来处理异常,例如将可能会出现不能被0整除异常的代码写在try代码块里,try代码块里的代码执行过程中出现异常后,就会执行except代码块里的代码,代码示例:
# 会出现异常的代码写在try里  
try:
  
    num=10/0
  
    print(num)  # 如果上面的代码出现异常这句代码不会被执行
  
except:
  
    print("出现异常了!")   # try里的代码出现异常后就会执行这里的代码
  运行结果:
  出现异常了!
  try语句按照如下方式工作;

  •   首先,执行try子句(在关键字try和关键字except之间的语句)
  •   如果没有异常发生,会忽略except子句,try子句执行后就结束。
  •   如果在执行try子句的过程中发生了异常,那么try子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的except子句将被执行。最后执行 try 语句之后的代码。
  •   如果一个异常没有与任何的except匹配,那么这个异常将会被抛出。
  一个 try 语句可以包含多个except子句,分别来处理不同的特定的异常。但是最多只有一个分支会被执行。
  以上示例的是最简单的使用方式,能够捕获所有类型的异常,称之为通用异常陷阱。如果需要捕捉特定的异常,可以在except中声明异常的类型,那么这个陷阱就只能捕获你所声明的异常类型,但是可以在末尾写上一个通用异常陷阱,没有被特定的陷阱所捕获的异常最后就会被通用异常陷阱所捕获。如果你在except中声明了一个异常类型,可以通过as关键字赋值给一个变量,通过这个变量可以打印出错误信息,代码示例:
try:  
    num = 10 / 0
  
    print(num)
  

  
except ZeroDivisionError as err: # 赋值给err变量
  
    print("出现异常:", err)
  
except TypeError:  # 声明一个指定的异常类型
  
    print("出现类型异常!")
  
except:    # 末尾可以使用一个通用异常
  
    print("出现异常了!")
  运行结果:
  出现异常: division by zero
  一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组,例如:
  except (RuntimeError, TypeError, NameError):
  使用raise关键字,可以将异常再次抛出,会抛出到解释器中,代码示例:
try:  
    num = 10 / 0
  
    print(num)
  

  
except ZeroDivisionError as err: # 赋值给err变量
  
    print("出现异常:", err)
  
    raise
  
except TypeError:  # 声明一个指定的异常类型
  
    print("出现类型异常!")
  
except:    # 末尾可以使用一个通用异常
  
    print("出现异常了!")
  运行结果:
出现异常: division by zero  
Traceback (most recent call last):
  
  File "E:/PythonProject/TestExcept.py", line 2, in <module>
  
    num = 10 / 0
  
ZeroDivisionError: division by zero
  try except 语句还有一个可选的else子句,这个子句必须放在所有的except子句之后。这个子句将在try子句没有发生任何异常的时候执行。例如:
try:  
    num = 1+1
  
except ZeroDivisionError as err: # 赋值给err变量
  
    print("出现异常:", err)
  
    raise
  
except TypeError:  # 声明一个指定的异常类型
  
    print("出现类型异常!")
  
except:    # 末尾可以使用一个通用异常
  
    print("出现异常了!")
  
else :
  
    print("没有出现异常!")
  运行结果:
  没有出现异常!
  使用 else 子句比把所有的语句都放在 try 子句里面要好,这样可以避免一些意想不到的、而except又没有捕获的异常。
  异常处理并不仅仅处理那些直接发生在try子句中的异常,而且还能处理子句中调用的函数(甚至间接调用的函数)里抛出的异常。例如:
def errorTest():  
    return 1/0
  

  
try:
  
    num = errorTest()
  
except ZeroDivisionError as err: # 赋值给err变量
  
    print("出现异常:", err)
  
except TypeError:  # 声明一个指定的异常类型
  
    print("出现类型异常!")
  
except:    # 末尾可以使用一个通用异常
  
    print("出现异常了!")
  
else :
  
    print("没有出现异常!")
  运行结果:
  出现异常: division by zero
抛出异常
  上面示例也用到了raise 关键字,通过这个关键字可以抛出异常到外部。也可以使用此关键字在代码中抛出特定的异常,如果这个关键字写在except里,并且没有指定要抛出的异常,那么这个raise 就会抛出这个陷阱里的异常,代码示例:
try:  
    num=10/0
  
except ZeroDivisionError:
  
    raise
  运行结果:
Traceback (most recent call last):  
  File "E:/PythonProject/TestExcept.py", line 3, in <module>
  
    num=10/0
  
ZeroDivisionError: division by zero
  使用raise 关键字抛出指定的异常示例:
i=0  
j=1
  

  
if i!=0:
  
    k=j/i
  
else:
  
    print("抛出一个异常:")
  
    raise ZeroDivisionError
  运行结果:
Traceback (most recent call last):  
  File "E:/PythonProject/TestExcept.py", line 8, in <module>
  
    raise ZeroDivisionError
  
ZeroDivisionError
  抛出的异常可以指定一个字符串类型的参数,这个参数也会随着异常信息打印出来,代码示例:
i=0  
j=1
  

  
if i!=0:
  
    k=j/i
  
else:
  
    print("抛出一个异常:")
  
    raise ZeroDivisionError("我是异常")
  运行结果:
抛出一个异常:  
Traceback (most recent call last):
  
  File "E:/PythonProject/TestExcept.py", line 9, in <module>
  
    raise ZeroDivisionError("我是异常")
  
ZeroDivisionError: 我是异常
用户自定义异常
  你可以通过创建一个新的exception类来拥有自己的异常。异常应该继承自 Exception 类,或者直接继承,或者间接继承,例如:
# 这是一个自定义的异常类  
>>> class MyError(Exception):  # 继承于Exception类
  
        def __init__(self, value):  # 这是初始化方法,也就是构造器
  
            self.value = value  #这是这个类的属性
  
        def __str__(self):   # 类中的每个方法都需要有一个self参数,通过这个参数来获取类属性的值
  
            return repr(self.value)
  

  
>>> try:
  
        raise MyError(2*2)  #抛出自定义的异常类
  
    except MyError as e:
  
        print('My exception occurred, value:', e.value)  #会被这里捕获
  

  
My exception occurred, value: 4   # 运行结果
  

  
>>> raise MyError('oops!')  # 抛出自定义的异常类
  

  
# 打印的异常信息
  
Traceback (most recent call last):
  
  File "<stdin>", line 1, in ?
  
__main__.MyError: 'oops!'
  在这个例子中,类 Exception 默认的 _init_( ) 被覆盖。
  当创建一个模块有可能抛出多种不同的异常时,一种通常的做法是为这个包建立一个基础异常类,然后基于这个基础类为不同的错误情况创建不同的子类:
class Error(Exception):  
    """Base class for exceptions in this module."""
  
    pass
  

  
class InputError(Error):
  
    """Exception raised for errors in the input.
  

  
    Attributes:
  
        expression -- input expression in which the error occurred
  
        message -- explanation of the error
  
    """
  

  
    def __init__(self, expression, message):
  
        self.expression = expression
  
        self.message = message
  

  
class TransitionError(Error):
  
    """Raised when an operation attempts a state transition that's not
  
    allowed.
  

  
    Attributes:
  
        previous -- state at beginning of transition
  
        next -- attempted new state
  
        message -- explanation of why the specific transition is not allowed
  
    """
  

  
    def __init__(self, previous, next, message):
  
        self.previous = previous
  
        self.next = next
  
        self.message = message
  大多数的异常的名字都以”Error”结尾,就跟标准的异常命名一样。
finally语句
  try 语句还有另外一个可选的子句,这个语句无论在任何情况下都会执行,也就是所谓的最终执行块,这个代码块里的代码不管什么有没有发生异常都会被执行,一般用于执行close之类的关闭资源的语句。 例如:
try:  
    filedata = open("E:/test.txt")
  
except IOError:
  
    print("文件打开失败!")
  
finally:
  
    filedata.close()
  
    print("资源已关闭!")
  运行结果:
  资源已关闭!
  以上例子不管 try 子句里面有没有发生异常,finally 子句都会执行。
  如果一个异常在 try 子句里(或者在 except 和 else 子句里)被抛出,而又没有任何的 except 把它截住,那么这个异常会在 finally 子句执行后再次被抛出。
  代码示例:
try:  
    filedata = open("E:/test.txt")
  
    raise ZeroDivisionError
  
except IOError:
  
    print("文件打开失败!")
  
finally:
  
    filedata.close()
  
    print("资源已关闭!")
  运行结果:
资源已关闭!  
Traceback (most recent call last):
  
  File "E:/PythonProject/TestExcept.py", line 3, in <module>
  
    raise ZeroDivisionError
  
ZeroDivisionError
预定义的清理行为
  一些对象定义了标准的清理行为,无论系统是否成功的使用了它,一旦不需要它了,那么这个标准的清理行为就会执行。
  这面这个例子展示了尝试打开一个文件,然后把内容打印到屏幕上:
for line in open("myfile.txt"):  
    print(line, end="")
  以上这段代码的问题是,当执行完毕后,文件会保持打开状态,并没有被关闭。
  之前介绍过的关键词 with 语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行他的清理方法,这种就是预定义的清理行为:
with open("myfile.txt") as f:  
    for line in f:
  
        print(line, end="")
  以上这段代码执行完毕后,就算在处理过程中出问题了,文件 f 也会关闭。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-549510-1-1.html 上篇帖子: 1到100累加计算python脚本 下篇帖子: Python练习题(day4)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表