八、异常和模块

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文件,这个文件控制着包的导入行为。

  1. 新建包mypackage
  2. 新建包内模块:my_module1my_module2
  3. 模块内代码如下
# 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()

九、多任务编程

  • 13
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值