文章目录
1.异常
当Python检测到一个错误时,解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的"异常"
1)捕获异常 try…except…
try:
可能发生错误的代码
except 异常类型:
如果出现异常执行的代码
看如下示例:
try:
print('-----test--1---')
open('123.txt','r')
print('-----test--2---')
except IOError:
pass
说明:
- 此程序看不到任何错误,因为用except 捕获到了IOError异常,并添加了处理的方法
- pass 表示实现了相应的实现,但什么也不做;如果把pass改为print语句,那么就会输出其他信息
小总结:
- 把可能出现问题的代码,放在try中
- 把处理异常的代码,放在except中
2)except捕获多个异常
捕获多个异常的方式,如下:
#coding=utf-8
try:
print('-----test--1---')
open('123.txt','r') # 如果123.txt文件不存在,那么会产生 IOError 异常
print('-----test--2---')
print(num)# 如果num变量没有定义,那么会产生 NameError 异常
except (IOError,NameError):
#如果想通过一次except捕获到多个异常可以用一个元组的方式
注意:
- 当捕获多个异常时,可以把要捕获的异常的名字,放到except 后,并使用元组的方式仅进行存储
3)获取异常的信息描述
try:
print(1/0)
except (NameError, ZeroDivisionError) as result:
print(result)
4)捕获所有异常
try:
print(num)
except Exception as result:
print(result)
5)else
在try…except…中也是如此,即如果没有捕获到异常,那么就执行else中的事情
try:
num = 100
print num
except NameError as errorMsg:
print('产生错误了:%s'%errorMsg)
else:
print('没有捕获到异常,真高兴')
6)try…finally…
try…finally…语句用来表达这样的情况:
在程序中,如果一个段代码必须要执行,即无论异常是否产生都要执行,那么此时就需要使用finally。 比如文件关闭,释放锁,把数据库连接返还给连接池等
demo:
import time
try:
f = open('test.txt')
try:
while True:
content = f.readline()
if len(content) == 0:
break
time.sleep(2)
print(content)
except:
#如果在读取文件的过程中,产生了异常,那么就会捕获到
#比如 按下了 ctrl+c
pass
finally:
f.close()
print('关闭文件')
except:
print("没有这个文件")
说明:
test.txt文件中每一行数据打印,但是我有意在每打印一行之前用time.sleep方法暂停2秒钟。这样做的原因是让程序运行得慢一些。在程序运行的时候,按Ctrl+c中断(取消)程序。
我们可以观察到KeyboardInterrupt异常被触发,程序退出。但是在程序退出之前,finally从句仍然被执行,把文件关闭。
7)异常的传递
try嵌套中
import time
try:
f = open('test.txt')
try:
while True:
content = f.readline()
if len(content) == 0:
break
time.sleep(2)
print(content)
finally:
f.close()
print('关闭文件')
except:
print("没有这个文件")
函数嵌套调用中
def test1():
print("----test1-1----")
print(num)
print("----test1-2----")
def test2():
print("----test2-1----")
test1()
print("----test2-2----")
def test3():
try:
print("----test3-1----")
test1()
print("----test3-2----")
except Exception as result:
print("捕获到了异常,信息是:%s"%result)
print("----test3-2----")
test3()
print("------华丽的分割线-----")
test2()
总结:
- 如果try嵌套,那么如果里面的try没有捕获到这个异常,那么外面的try会接收到这个异常,然后进行处理,如果外边的try依然没有捕获到,那么再进行传递。。。
- 如果一个异常是在一个函数中产生的,例如函数A---->函数B---->函数C,而异常是在函数C中产生的,那么如果函数C中没有对这个异常进行处理,那么这个异常会传递到函数B中,如果函数B有异常处理那么就会按照函数B的处理方式进行执行;如果函数B也没有异常处理,那么这个异常会继续传递,以此类推。。。如果所有的函数都没有处理,那么此时就会进行异常的默认处理,即通常见到的那样
- 当调用test3函数时,在test1函数内部产生了异常,此异常被传递到test3函数中完成了异常处理,而当异常处理完后,并没有返回到函数test1中进行执行,而是在函数test3中继续执行
8)抛出自定义的异常
可以用raise语句来引发一个异常。异常/错误对象必须有一个名字,且它们应是Error或Exception类的子类
下面是一个引发异常的例子:
class ShortInputException(Exception):
'''自定义的异常类'''
def __init__(self, length, atleast):
#super().__init__()
self.length = length
self.atleast = atleast
def main():
try:
s = input('请输入 --> ')
if len(s) < 3:
# raise引发一个你定义的异常
raise ShortInputException(len(s), 3)
except ShortInputException as result:#x这个变量被绑定到了错误的实例
print('ShortInputException: 输入的长度是 %d,长度至少应是 %d'% (result.length, result.atleast))
else:
print('没有异常发生.')
main()
注意
-
以上程序中,关于代码
#super().__init__()
的说明
这一行代码,可以调用也可以不调用,建议调用,因为
__init__
方法往往是用来对创建完的对象进行初始化工作,如果在子类中重写了父类的__init__
方法,即意味着父类中的很多初始化工作没有做,这样就不保证程序的稳定了,所以在以后的开发中,如果重写了父类的__init__
方法,最好是先调用父类的这个方法,然后再添加自己的功能
2.模块
Python 模块(Module),是⼀个 Python ⽂件,以 .py 结尾,包含了 Python 对象定义和Python语句。
模块能定义函数,类和变量,模块⾥也能包含可执⾏的代码。
1)导⼊模块的⽅式
- import 模块名
- from 模块名 import 功能名
- from 模块名 import *
- import 模块名 as 别名
- from 模块名 import 功能名 as 别名
2)import
-
语法
# 1. 导⼊模块 import 模块名 import 模块名1, 模块名2... # 2. 调⽤功能 模块名.功能名()
import math print(math.sqrt(9)) # 3.0
2) from…import…
-
语法
from 模块名 import 功能1, 功能2, 功能3...
-
体验
from math import sqrt print(sqrt(9))
3)from … import
-
语法
from 模块名 import *
-
体验
from math import * print(sqrt(9))
4)as定义别名
-
语法
# 模块定义别名 import 模块名 as 别名 # 功能定义别名 from 模块名 import 功能 as 别名
-
体验
# 模块别名 import time as tt tt.sleep(2) print('hello') # 功能别名 from time import sleep as sl sl(2) print('hello')
5)模块中的__all__
如果⼀个模块⽂件中有 all 变量,当使⽤ from xxx import * 导⼊时,只能导⼊这个列表中的元素。
-
my_module1模块代码
__all__ = ['testA'] def testA(): print('testA') def testB(): print('testB')
-
导⼊模块的⽂件代码
from my_module1 import * testA() testB()
总结
- 如果一个文件中有__all__变量,那么也就意味着不在这个变量中的元素,不会被from xxx import *时导入
3.模块制作
在Python中,每个Python⽂件都可以作为⼀个模块,模块的名字就是⽂件的名字。也就是说⾃定义模块名必须要符合标识符命名规则。
1)定义模块
在Python中,每个Python文件都可以作为一个模块,模块的名字就是文件的名字。
比如有这样一个文件test.py,在test.py中定义了函数add
test.py
def add(a, b):
print(a + b)
2)调用模块
那么在其他文件中就可以先import test,然后通过test.add(a,b)来调用了,当然也可以通过from test import add来引入
main.py
import my_module1
my_module1.add(1, 1)
3)测试模块
在实际开中,当一个开发人员编写完一个模块后,为了让模块能够在项目中达到想要的效果,这个开发人员会自行在py文件中添加一些测试信息,例如:
def add(a,b):
return a+b
if __name__ == '__main__':
ret = add(12,22)
print('int test.py file,,,,12+22=%d'%ret)
至此,可发现test.py中的测试代码,应该是单独执行test.py文件时才应该执行的,不应该是其他的文件中引用而执行
为了解决这个问题,python在执行一个文件时有个变量__name__
注意事项
如果使用from .. import ..
或from .. import *
导入多个模块的时候,且模块内有同名功能。当调用这个同名功能的时候,调用到的是后面导入的模块的功能。
# 模块1代码
def my_test(a, b):
print(a + b)
# 模块2代码
def my_test(a, b):
print(a - b)
# 导入模块和调用功能代码
from my_module1 import my_test
from my_module2 import my_test
# my_test函数是模块2中的函数
my_test(1, 1)
总结:
- 可以根据__name__变量的结果能够判断出,是直接执行的python脚本还是被引入执行的,从而能够有选择性的执行测试代码
4.python中的包
包将有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为__init__.py
文件,那么这个文件夹就称之为包。
1) 制作包
[New] — [Python Package] — 输入包名 — [OK] — 新建功能模块(有联系的模块)。
注意:新建包后,包内部会自动创建__init__.py
文件,这个文件控制着包的导入行为。
- 新建包
mypackage
- 新建包内模块:
my_module1
和my_module2
- 模块内代码如下
# my_module1
print(1)
def info_print1():
print('my_module1')
# my_module2
print(2)
def info_print2():
print('my_module2')
2) 导入包
方法一
import 包名.模块名
包名.模块名.目标
import my_package.my_module1
my_package.my_module1.info_print1()
方法二
注意:必须在__init__.py
文件中添加__all__ = []
,控制允许导入的模块列表。
from 包名 import *
模块名.目标
from my_package import *
my_module1.info_print1()