python程序在编写和运行过程中会产生一些错误,这些错误会导致程序不能按照用户的意图进行工作,甚至由于某些错误的存在,导致程序无法正常运行,或者导致程序终止执行,我们就需要处理这些错误,使得程序能够正常运行。错误在帮助我们尽快修改程序方面起到了非常重要的作用。
程序中常见的错误有语法错误,语义错误,逻辑错误:
简言之,由于程序中的错误,使得程序产生了一些异常行为,我们就需要及时发现并纠正异常行为,从而保证程序的正确运行。
在程序中,异常(exception) 是程序运行过程中发生的事件, 该事件可以中断程序指令的正常执行流程. 一般情况下,当python无法正确处理程序时会抛出异常,如果不处理异常,将会导致程序终止运行。
- try:
- # 可能会抛出异常的代码段
- except 异常类型:
- # 处理异常的代码
在if中,是当条件不满足时执行的实行;同样在try...except...中也是如此,即如果没有捕获到异常,那么就执行else中的事情。
- try:
- f = open("log.txt","r")
- a = 10
- b = 1
- ret = a / b
-
- #捕获多个类型的异常
- except IOError as ex:
- print(ex)
- except ZeroDivisionError as ex:
- print(ex)
- else:
- print("没有异常,真是happy!")
try...finally...语句用来表达这样的情况:在程序中,如果一个段代码无论异常是否产生都要执行,那么此时就需要使用finally
- try:
- f = open("log.txt","r")
- a = 10
- b = 0
- ret = a / b
-
- #捕获多个类型的异常
- except IOError as ex:
- print(ex)
- except ZeroDivisionError as ex:
- print(ex)
- else:
- print("没有异常,真是happy!")
- finally:
- print("无论是否异常发生,都会执行!")
- import time
- try:
- f = open('log.txt')
- try:
- while True:
- content = f.readline()
- if len(content) == 0:
- break
- time.sleep(2)
- print(content)
- finally:
- f.close()
- print('关闭文件')
- except:
- print("没有这个文件")
| BaseException | 所有异常的基类 |
| SystemExit | 解释器请求退出 |
| KeyboardInterrupt | 用户中断执行(通常是输入^C) |
| Exception | 常规错误的基类 |
| StopIteration | 迭代器没有更多的值 |
| GeneratorExit | 生成器(generator)发生异常来通知退出 |
| StandardError | 所有的内建标准异常的基类 |
| ArithmeticError | 所有数值计算错误的基类 |
| FloatingPointError | 浮点计算错误 |
| OverflowError | 数值运算超出最大限制 |
| ZeroDivisionError | 除(或取模)零 (所有数据类型) |
| AssertionError | 断言语句失败 |
| AttributeError | 对象没有这个属性 |
| EOFError | 没有内建输入,到达EOF 标记 |
| EnvironmentError | 操作系统错误的基类 |
| IOError | 输入/输出操作失败 |
| OSError | 操作系统错误 |
| WindowsError | 系统调用失败 |
| ImportError | 导入模块/对象失败 |
| LookupError | 无效数据查询的基类 |
| IndexError | 序列中没有此索引(index) |
| KeyError | 映射中没有这个键 |
| MemoryError | 内存溢出错误(对于Py解释器不是致命的) |
| NameError | 未声明/初始化对象 (没有属性) |
| UnboundLocalError | 访问未初始化的本地变量 |
| ReferenceError | 弱引用试图访问已经垃圾回收了的对象 |
| RuntimeError | 一般的运行时错误 |
| NotImplementedError | 尚未实现的方法 |
| SyntaxError | Python 语法错误 |
| IndentationError | 缩进错误 |
| TabError | Tab 和空格混用 |
| SystemError | 一般的解释器系统错误 |
| TypeError | 对类型无效的操作 |
| ValueError | 传入无效的参数 |
| UnicodeError | Unicode 相关的错误 |
| UnicodeDecodeError | Unicode 解码时的错误 |
| UnicodeEncodeError | Unicode 编码时错误 |
| UnicodeTranslateError | Unicode 转换时错误 |
| Warning | 警告的基类 |
| DeprecationWarning | 关于被弃用的特征的警告 |
| FutureWarning | 关于构造将来语义会有改变的警告 |
| OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
| PendingDeprecationWarning | 关于特性将会被废弃的警告 |
可以用raise语句来引发一个异常。通过创建一个新的异常类,程序可以命名它们自己的异常。异常应该是典型的继承自Exception类,通过直接或间接的方式。
- # 自定义异常类
- class OutOfRangeException(Exception):
- def __init__(self,errMsg):
- self.msg = errMsg
-
- def __str__(self):
- return self.msg
-
-
- class Person(object):
- def __init__(self):
- self.name = None
- self.age = None
-
- def setAge(self,age):
- if age < 0 or age > 100:
- raise OutOfRangeException("年龄应该在0-100之间!")
- self.age = age
-
- def setName(self,name):
- self.name = name
-
- def __str__(self):
- return "name:{} age:{}".format(self.name,self.age)
-
- if __name__ == "__main__":
- person = Person()
- person.setName("Edward")
- person.setAge(80)
- print(person)
- try:
- person.setAge(101)
- except OutOfRangeException as ex:
- print(ex)
如果try嵌套,那么如果里面的try没有捕获到这个异常,那么外面的try会接收到这个异常,然后进行处理,如果外边的try依然没有捕获到,那么再进行传递。
如果一个异常是在一个函数中产生的,例如函数A---->函数B---->函数C,而异常是在函数C中产生的,那么如果函数C中没有对这个异常进行处理,那么这个异常会传递到函数B中,如果函数B有异常处理那么就会按照函数B的处理方式进行执行;如果函数B也没有异常处理,那么这个异常会继续传递,以此类推。。。如果所有的函数都没有处理,那么此时就会进行异常的默认处理,即通常见到的那样。
当调用test3函数时,在test1函数内部产生了异常,此异常被传递到test3函数中完成了异常处理,而当异常处理完后,并没有返回到函数test1中进行执行,而是在函数test3中继续执行。
比如,编写了一个模块mymodule.py,在该模块中我们定义一些函数和类,在other.py使用
mymodule.py:
- # Person类
- class Person(object):
- def __init__(self,name,age):
- self.name = name
- self.age = age
-
- def showPerson(self):
- print("Name:%s Age:%d"%(self.name,self.age))
-
- # 函数
- def myAdd(a,b):
- ret = a + b
- return ret
other.py
- # 引入mymodule模块
- import mymodule
-
- # 使用mymodule模块中的myAdd函数
- # 注意在使用mymodule中的符号的时候,必须指定模块名.符号的方式
- ret = mymodule.myAdd(10,20)
- print("ret = %d"%ret)
-
- # 使用mymodule模块中的Person类
- person= mymodule.Person("Edward",22)
- person.showPerson()
为什么必须加上模块名调用
因为可能存在这样一种情况:在多个模块中含有相同名称的函数,此时如果只是通过函数名来调用,解释器无法知道到底要调用哪个函数。所以如果像上述这样引入模块的时候,调用函数必须加上模块名.
有时候我们只需要用到模块中的某个函数,只需要引入该函数即可.通过这种方式引入的时候,调用函数时只能给出函数名,不能给出模块名,但是当两个模块中含有相同名称函数的时候,后面一次引入会覆盖前一次引入。
例如:模块A中有函数function( ),在模块B中也有函数function( ),如果引入A中的function在先、B中的function在后,那么当调用function函数的时候,是去执行模块B中的function函数。如果想一次性引入math中所有的东西,还可以通过from math import *来实现。
- # 引入mymodule模块中的myAdd函数
- from mymodule import myAdd
-
- # 使用mymodule模块中的myAdd函数
- # 注意不可添加模块名
- ret = myAdd(10,20)
- print("ret = %d"%ret)
-
- # 使用mymodule模块中的Person类出错
- # person= mymodule.Person("Edward",22)
- # person.showPerson()
- # 使用import xxx import *
- # 引入mymodule模块中的所有符号
- from mymodule import *
-
- # 使用mymodule模块中的myAdd函数
- # 注意不可添加模块名
- ret = myAdd(10,20)
- print("ret = %d"%ret)
-
- # 使用mymodule模块中的Person类出错
- person= Person("Edward",22)
- person.showPerson()
这提供了简单的方法导入模块中的所有项目, 然而这种方法不应被过多使用。
将引入的模块重新命名:
- # 引入mymodule并重新命名为md
- # 此时再使用mymodule就会未定义
- import mymodule as md
-
- # 使用mymodule模块中的myAdd函数
- # 注意不可添加模块名
- ret = md.myAdd(10,20)
- print("ret = %d"%ret)
-
- # 使用mymodule模块中的Person类出错
- person= md.Person("Edward",22)
- person.showPerson()
当导入一个模块,Python对模块位置的搜索顺序是:
模块搜索路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。
我们可通过配置PYTHONPATH变量、sys.path.append、.pth来添加搜索目录。
使用from import * 导入某个模块中的符号时,假如我们只想导入部分符号(函数、类、变量),可以通过__all__可以指定那些符号可导出.__all__是一个字符串类型的列表。
- __all__ = ["my_function"]
-
- def my_function():
- print("my_function!")
-
- def temp_function():
- print("temp_function!")
为了更好管理模块,将多个模块放到一个文件夹中,这个文件夹就叫做包,但是此文件夹下必须包含__init__.py文件,该__init__文件可以为空。__init__文件主要用于标识该目录是一个包。
包是一个分层次的文件目录结构,它定义了一个由模块及子包,和子包下的子包组成的Python应用环境。
- # 导入package包下mymodule模块
- # 方式一
- import package.mymodule
- package.mymodule.my_function()
-
- # 方式二
- # 需要在__init__.py文件
- # 添加__all__ = ["mymodule"]
- # 指定import *的模块
- from package import *
- mymodule.my_function()
-
- # 方式三
- # 导入模块中指定符号
- from package.mymodule import my_function
- my_function()
-
-
- # 引入subpackage包中mymodule2模块
- import package.subpackage.mymodule2
- package.subpackage.mymodule2.he_function()
-
- from package.subpackage import mymodule2
- mymodule2.he_function()
-
- from package.subpackage import *
- mymodule2.he_function()
总结: