Python学习Python中文社区python

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

2018-04-16  本文已影响30人  DragonFangQy

异常

什么是异常

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


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 文件的文件名。文件名将会用于标识符,所以文件名必须满足标识符的命名规则,否则不能导入。

导入

模块 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

导入包中的模块

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

上一篇下一篇

猜你喜欢

热点阅读