python基础知识整理 06-异常、模块和包

1 异常

1.1 概述

python程序在编写和运行过程中会产生一些错误,这些错误会导致程序不能按照用户的意图进行工作,甚至由于某些错误的存在,导致程序无法正常运行,或者导致程序终止执行,我们就需要处理这些错误,使得程序能够正常运行。错误在帮助我们尽快修改程序方面起到了非常重要的作用。

程序中常见的错误有语法错误,语义错误,逻辑错误:

  • 语法错误: 由于编写程序时没有遵守语法规则,编写了错误的代码,从而导致python解释器无法解释执行源代码而产生的错误。例如,缩进错误,非法字符等等。
  • 语义错误:指源程序中不符合语义规则的错误,一条语句视图执行一条不可能的操作而导致的错误。例如,变量定义错误,作用域错误等等。
  • 逻辑错误:指程序的运行结果和程序员的预期设想有出入而导致的错误。这类错误并不能直接导致程序运行出现错误,但是未按预期设想的方式运行,产生了不正确的结果。例如:年龄的有效范围为1-100,结果得到的数据超出范围。

简言之,由于程序中的错误,使得程序产生了一些异常行为,我们就需要及时发现并纠正异常行为,从而保证程序的正确运行。

在程序中,异常(exception) 是程序运行过程中发生的事件, 该事件可以中断程序指令的正常执行流程. 一般情况下,当python无法正确处理程序时会抛出异常,如果不处理异常,将会导致程序终止运行。

1.2 异常语法

1.2.1 格式

try: 
    # 可能会抛出异常的代码段 
except 异常类型: 
    # 处理异常的代码

1.2.2 else用法

在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!")

1.2.3 finally用法

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("无论是否异常发生,都会执行!")

1.2.4 try嵌套

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("没有这个文件")

1.2.5 自定义异常

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)

1.3 总结

如果try嵌套,那么如果里面的try没有捕获到这个异常,那么外面的try会接收到这个异常,然后进行处理,如果外边的try依然没有捕获到,那么再进行传递。

如果一个异常是在一个函数中产生的,例如函数A---->函数B---->函数C,而异常是在函数C中产生的,那么如果函数C中没有对这个异常进行处理,那么这个异常会传递到函数B中,如果函数B有异常处理那么就会按照函数B的处理方式进行执行;如果函数B也没有异常处理,那么这个异常会继续传递,以此类推。。。如果所有的函数都没有处理,那么此时就会进行异常的默认处理,即通常见到的那样。

当调用test3函数时,在test1函数内部产生了异常,此异常被传递到test3函数中完成了异常处理,而当异常处理完后,并没有返回到函数test1中进行执行,而是在函数test3中继续执行。

2 模块和包

2.1 使用模块

2.1.1 import

比如,编写了一个模块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()

为什么必须加上模块名调用

因为可能存在这样一种情况:在多个模块中含有相同名称的函数,此时如果只是通过函数名来调用,解释器无法知道到底要调用哪个函数。所以如果像上述这样引入模块的时候,调用函数必须加上模块名.

2.1.2 from...import...

有时候我们只需要用到模块中的某个函数,只需要引入该函数即可.通过这种方式引入的时候,调用函数时只能给出函数名,不能给出模块名,但是当两个模块中含有相同名称函数的时候,后面一次引入会覆盖前一次引入。

例如:模块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()

这提供了简单的方法导入模块中的所有项目, 然而这种方法不应被过多使用。

2.1.3 import...as...

将引入的模块重新命名:

# 引入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()

2.1.4 定位模块

当导入一个模块,Python对模块位置的搜索顺序是:

  • 当前目录;
  • PYTHONPATH目录;
  • 标准库目录;
  • .pth文件目录

模块搜索路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。

我们可通过配置PYTHONPATH变量、sys.path.append、.pth来添加搜索目录。

2.2 __all__作用

使用from import * 导入某个模块中的符号时,假如我们只想导入部分符号(函数、类、变量),可以通过__all__可以指定那些符号可导出.__all__是一个字符串类型的列表。

__all__ = ["my_function"]

def my_function():
    print("my_function!")

def temp_function():
    print("temp_function!")

2.3 包

为了更好管理模块,将多个模块放到一个文件夹中,这个文件夹就叫做包,但是此文件夹下必须包含__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()

总结:

  • 包是一个文件目录
  • python包中要包含文件__init__.py
  • __init__.py文件中__all__变量可指定from package import *导入的模块
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

轨迹|

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值