美文网首页Python学习Python中文社区python
Python学习笔记九(异常、模块)

Python学习笔记九(异常、模块)

作者: DragonFangQy | 来源:发表于2018-04-16 19:49 被阅读30次

    异常

    什么是异常

    程序发生错误,既程序非正常终止,则为异常。异常会让程序终止,这样的程序很不友好,我们希望程序异常结束时能给出提示。

    
    1/0
    
    # 结果为:
    # Traceback (most recent call last):
    #   File "E:/workspace/pycharm/pycharm/Demo.py", line 1, in <module>
    #     1/0
    # ZeroDivisionError: division by zero
    
    
    

    捕获异常

    try ... except ... 用于捕获异常,处理异常,程序在一次运行中只会产生一个异常。

    格式

    
    try:
        pass
    except:
        pass
    
    
    

    一个try 可以配合多个except 使用,每一个except 认为是一个分支。

    
    try:
        1 / 0
    except:
        print("发生异常程序,即将退出")
    
    # 结果为:
    # 发生异常程序,即将退出
    
    
    

    捕获异常,作出提示,程序的友好性有所提升。

    捕获异常的方式
    • 单分支捕获指定异常
    • 单分支捕获指定多个异常
    • 多分支捕获异常
    • 单分支捕获常见异常

    捕获指定异常

    捕获指定异常(一个分支捕获一个异常)

    
    try:
        1 / 0
    except ZeroDivisionError:
        print("被除数不能为 0")
    
    # 结果为:
    # 被除数不能为 0
    
    

    如果需要获得异常的一些信息怎么办?使用 as 为异常对象起一个别名

    
    try:
        1 / 0
    except ZeroDivisionError as exc:
        print("被除数不能为 0 ,"
              "异常信息:%s ,"
              "异常代码所在的行数:%d" % (exc, exc.__traceback__.tb_lineno))
    
    # 结果为:
    # 被除数不能为 0 ,异常信息:division by zero ,异常代码所在的行数:2
    
    
    

    单分支指定捕获多个异常

    当多个异常处理逻辑相同时,可以放在一个分支中进行处理。

    
    try:
        # max()  # TypeError
        # max([])  # ValueError
        pass
    except (TypeError, ValueError) as exc:
        print("异常信息:%s ,"
              "异常代码的行数:%d" % (exc, exc.__traceback__.tb_lineno))
    
    
    

    通过元组的形式可以在一个分支指定捕获多个异常,但是每次只有一个异常被捕获处理,为啥?因为一次只会产生一个异常。

    多分支捕获异常

    
    try:
        max()  # TypeError
        # max([])  # ValueError
    
    except ValueError as exc:
        print("异常信息:%s ,"
              "异常代码的行数:%d" % (exc, exc.__traceback__.tb_lineno))
    except TypeError as exc:
        print("异常信息:%s ,"
              "异常代码的行数:%d" % (exc, exc.__traceback__.tb_lineno))
    
    
    

    单分支捕获常见异常

    
    try:
        max()  # TypeError
        # max([])  # ValueError
    
    except Exception as exc:  # 单分支捕获常见异常
        print("异常信息:%s ,"
              "异常代码的行数:%d" % (exc, exc.__traceback__.tb_lineno))
    
    
    # Exception 的直接子类
    # ArithmeticError(Exception)
    # AssertionError(Exception)
    # AttributeError(Exception)
    # WindowsError(Exception)
    # BufferError(Exception)
    # Warning(Exception)
    # EOFError(Exception)
    # ImportError(Exception)
    # SyntaxError(Exception)
    # LookupError(Exception)
    # MemoryError(Exception)
    # NameError(Exception)
    # RuntimeError(Exception)
    # ReferenceError(Exception)
    # StopAsyncIteration(Exception)
    # StopIteration(Exception)
    # SystemError(Exception)
    # TypeError(Exception)
    # ValueError(Exception)
    # 19 个
    
    
    

    异常的传递

    def func1():
        1 / 0
    
    def func2():
        func1()
    
    def func3():
        func2()
    
    func3()
    
    # 结果为:
    # Traceback (most recent call last):
    #   File "E:/workspace/pycharm/pycharm/Demo.py", line 10, in <module>
    #     func3()
    #   File "E:/workspace/pycharm/pycharm/Demo.py", line 8, in func3
    #     func2()
    #   File "E:/workspace/pycharm/pycharm/Demo.py", line 5, in func2
    #     func1()
    #   File "E:/workspace/pycharm/pycharm/Demo.py", line 2, in func1
    #     1 / 0
    # ZeroDivisionError: division by zero
    
    
    
    
    异常的传递

    通过错误日志可以看出来在第十行调用了func3 ,func3 调用了 func2 ,func2 调用了func1 ,在行2 也就是func1 里面出错,没有处理错误,错误向上传递到func2 ,再传给func3 ,直到func3 的调用处都没有处理异常,程序异常终止。

    自定义异常

    
    class UserDefinedException(Exception):  # 继承Exception类
        '''自定义的异常类'''
    
        def __init__(self):
            pass
    
    raise UserDefinedException()  # 使用raise 抛出一个UserDefinedException 异常
    
    
    

    模块

    什么是模块

    一个 .py 文件就是一个模块,作用:分工,一个人负责某几个模块。

    模块的导入

    什么是模块名

    前面已经说了一个 .py 文件就是一个模块,所以模块名就是 .py 文件的文件名。文件名将会用于标识符,所以文件名必须满足标识符的命名规则,否则不能导入。

    导入

    • import 模块名
    • form 模块名 import 功能

    模块 piece.py 的内容

    
    def func():
        print("------ piece func -----------")
    
    
    

    使用import 导入

    
    import piece  # impotent 模块名,直接找人帮忙
    
    piece.func()  # 模块名.功能名 使用,功能包括模块中的方法、变量、类等都可以使用。
    
    # 结果为:
    # ------ piece func -----------
    
    
    
    # as 定义别名,结合import 使用 
    import piece as p  # 使用as 给模块名 定义别名
    
    p.func()  # 别名.功能名
    
    # 结果为:
    # ------ piece func -----------
      
      
    

    import 导入可以理解为交了一个朋友(导入模块),比如说你的朋友会做做菜(模块中的功能),如果你需要做菜(想使用模块中的功能),你得先找到你的朋友(通过模块名),然后让他帮你做菜(调用功能)

    form 模块名 import 功能

    
    from piece import func  # form 模块名 import 功能,只能导入指定的功能
    
    func()  # 直接使用
    
    # 结果为:
    # ------ piece func -----------
      
    
    
    # as 结合 form import 使用
    
    # form 模块名 import 功能 as 别名,功能包括模块中的方法、变量、类等都可以使用。
    from piece import func as f 
    
    f()  # 直接使用
    
    # 结果为:
    # ------ piece func -----------
      
      
    
    

    form import 的形式:还是用做菜来说吧,你有一个朋友会做菜(模块名),一顿烧烤,你从他那里学会了几道菜(功能),你学会了之后,想做菜了,还需要找朋友来帮忙吗?!你要是觉得别人帮你理所应当我也没法!!!继续,你都会了,当然是自己下厨了(使用功能)。

    from 模块名 import *

    导入模块中的所有公开部分

    
    from piece import *  # from 模块名import 星号 
    
    func()  # 直接使用
    
    
    

    看上面的代码和导入指定的功能没什么区别,那为什么说 星号 是导入所有公开部分和import 模块有什么区别呢?
    首先,说一下from 模块名 import * 怎么理解,可以理解为你的朋友会做菜,会修车等等,你一顿烧烤学会做菜(公共的功能),但是他没教你修车(公共功能,但是我不想教你),所以你只会做菜(只能使用做菜,不能使用修车)。
    通过上面的叙述应该可以明白 星号 是导入所有公开部分和import 模块的区别。区别在于找朋友帮忙,只要朋友会他就能帮你做(import)。但是你从朋友那里学 (from import *),他不教,你就不会。

    那么有一个问题,星号是怎么知道你的朋友有哪些是想教给你,哪些不想的呢?__all__ 变量

    __all__ 变量

    通过前面可以知道__all__ 变量 的作用是控制 星号 可以导入的功能,也只对 星号 起作用。

    piece.py

    
    __all__ = ["func","func3"]  # __all__ 变量,赋值列表,列表中的每个元素都是功能名称的字符串
       
    def func():
        print("------ piece func -----------")
    
    
    def func2():
        print("------ piece func -----------")
    
    
    def func3():
        print("------ piece func -----------")
    
    
    
    

    使用 星号 导入

    
    from piece import *
    
    func()
    func3()
    func2()
    
    # 结果为:
    # ------ piece func -----------
    # Traceback (most recent call last):
    # ------ piece func3 -----------
    #   File "E:/workspace/pycharm/pycharm/Demo.py", line 7, in <module>
    #     func2()
    # NameError: name 'func2' is not defined
    
    # 结果分析:
    # 通过结果可以看出,__all__ 变量中的功能都正常运行,不在__all__ 中的功能不能使用
    
    
    

    模块与路径

    导入模块,会了,那么导入模块是根据什么导入的呢?比如说系统有个random 模块,我的工程目录下有一个random 模块,是导入我工程目录下的random ,还是 系统中的random ?往下看

    
    
    import piece
    import sys
    import os
    
    print(piece.__file__)  # 模块有一个__file__属性,可以查看当前导入的模块的存放路径
    print(os.getcwd())  # 获取当前工作路径
    print(sys.path)  # 获取系统搜索导入模块会查看的路径
     
    # 结果为:
    # E:\workspace\pycharm\pycharm\piece.py
    # E:\workspace\pycharm\pycharm
    # ['E:\\workspace\\pycharm\\pycharm', 
    # 'E:\\workspace\\pycharm\\pycharm', 'D:\\software\\Python36\\python36.zip', 
    # 'D:\\software\\Python36\\DLLs', 'D:\\software\\Python36\\lib', 
    # 'D:\\software\\Python36', 'D:\\software\\Python36\\lib\\site-packages']
    
    # 结果分析:
    # sys.path 搜索路径是一个列表,列表可以增删改查,列表的第一个元素是当前的工作路径,
    # 所以当工作路径下有一个和系统模块重名的模块时,会导入工作路径下的模块。
    # 问重名会不会有影响?首先不建议重名,那我怎么知道有没有重名?你不需要知道!为什么不需要知道?
    # 首先你知道系统有random 模块,你才会用系统的,如果说系统没有这个模块或者你不知道有这个模块,
    # 你还会用吗? 不会用吧?!那么在工作目录下创建一个random 模块来使用,有影响吗?
    
    
    

    自定义模块与测试

    自定义模块

    通俗点说就是自己写一个 .py 的文件,文件中包含一些功能。

    测试

    在自己的模块中写测试代码,测试模块功能。

    piece.py

    
    def func():
        print("------ piece func -----------")
    
    
    print(" piece 的测试")
    
    # 结果:
    #  piece 的测试  # 假设当前模块测试通过
    
    
    

    piece.py 被当做模块导入

    Demo.py 中导入piece 模块,直接运行Demo.py 文件

    
    import piece
    
    # 直接运行
    # 结果为:
    #  piece 的测试
    
    
    

    Demo.py文件中只有一句import ,为什么会有输出?输出的结果是不是有点眼熟?这不是模块中的测试代码吗?
    怎么解决这个问题?__name__变量

    修改模块piece

    
    def func():
        print("------ piece func -----------")
    
    
    if __name__ == "__main__":
        print(" piece 的测试")
    
    # 运行结果为:
    # __main__
    # piece 的测试
    
    
    

    修改Demo.py

    
    # import piece
    # import piece as p
    
    # 分别以 import形式 以及 别名形式导入
    # 运行结果:
    # piece
    # piece
    # 分析在piece 中直接运行的结果与piece 被当做模块导入Demo 文件中运行的结果可以发现
    # 在piece 直接piece 本身时,__name__的值为__main__,
    # 当piece 被当做模块导入Demo 文件中,运行Demo 文件时,piece 的__name__值为模块名,且不受别名的影响。
    
    
    

    import 没有继承

    piece1.py

    
    def func():
        print("------ piece1 func -----------")
    
    
    

    piece.py

    
    import piece1
    
    
    def func():
        print("------ piece func -----------")
    
    
    if __name__ == '__main__':
        piece1.func()
    
    
    

    Demo.py

    
    import piece
    
    if __name__ == '__main__':
        piece.func()
        piece1.func()
    
    # 执行结果:
    # ------ piece func -----------
    # Traceback (most recent call last):
    #   File "E:/workspace/pycharm/pycharm/Demo.py", line 5, in <module>
    #     piece1.func()
    # NameError: name 'piece1' is not defined
    
    
    

    怎么理解呢?朋友(piece)的朋友(piece1)并不是你(Demo)的朋友

    什么是包

    包就是文件夹或者目录,作用:归类,将功能相类似或者相关联的模块放在同一包下,方便管理

    在工程目录下新建文件夹,如果使用集成开发工具pytcharm 新建python package会自带__init__.py 文件,
    这个文件有什么作用呢?

    __init__.py文件

    __init__.py 是包的一个初始化文件,可以提供一个__all__变量(和模块中的__all__变量类似),初始化模块所需环境,python2中必须有这个文件。

    包名的格式

    com.XXX1.XXX2.XXX3
    . 的作用是分隔目录,如上有三个. 分隔了四层目录,com 下有XXX1,XXX1 下有XXX2 ,XXX2 下有XXX3

    导入包中的模块

    • import 包名.模块名
    • from 包名.模块名 import 功能名

    com.dragon_fang.demo 包下的模块 piece.py 的内容

    
    def func():
        print("------ piece func -----------")
    
    
    

    使用import 导入

    com.dragon_fang 包下的Demo.py

    
    import demo.piece  # impotent 包名.模块名,去找你的中国(包名)朋友(模块名)帮忙,导入指定的模块
    
    demo.piece.func()  # 包名.模块名.功能名 使用,功能包括模块中的方法、变量、类等都可以使用。
    
    # 结果为:
    # ------ piece func -----------
    
    
    
    # as 定义别名,结合import 使用 
    import demo.piece as p  # 使用as 定义别名,当包的层级比较深时,很好用
    
    p.func()  # 别名.功能名
    
    # 结果为:
    # ------ piece func -----------
      
      
    

    form 模块名 import 功能

    
    from demo import piece   # form 包名 import 模块名 ,导入指定的模块
    
    piece.func()  # 直接使用
    
    # 结果为:
    # ------ piece func -----------
      
    
    
    # as 结合 form import 使用
    
    # from demo import piece as 别名,为指定的模块起一个别名
    from demo import piece as p 
    
    p.func()  # 别名.功能
    
    # 结果为:
    # ------ piece func -----------
      
      
    
    

    from包名 import *

    导入包中的所有公开部分

    
    from demo import *  # from 包名 import 星号 
    
    piece.func()  # 模块.功能
    
    
    

    导入包中的模块的 import 和 from import 与 导入模块的 import 和 from import 类似,不做赘述。

    说一下 *(星号) 前面说过,包下有一个__init__.py 文件,文件中有一个__all__ 变量控制 *(星号) 可以导入包中的哪些模块,
    所有在__all__ 变量列表中以字符串存储的功能名才能被 *(星号) 导入。


    到此结   DragonFang   2018.4.16

    相关文章

      网友评论

        本文标题:Python学习笔记九(异常、模块)

        本文链接:https://www.haomeiwen.com/subject/rwzekftx.html