零基础小白的Python学习之路(七)异常、文件和模块


参考资料:《Python编程 从入门到实战》+ 尚学堂Python400集

异常(Exception)

在我们的日常生活中,软件程序的运行并不都是完美的,经常会出现一些我们意料之外的异常情况。这个时候,我们就需要一些异常处理的机制能够保证在异常发生时,能够正确处理异常,保证用户的使用。

比如,我们要从D盘拷贝一个文件到E盘,拷贝函数的代码只有短短一行语句,但是为了判断能不能拷贝,我们需要考虑多方面因素:这个文件是否存在?E盘的空间够不够?如果文件复制到一半,因系统出现了别的情况导致复制过程中段怎么办?

Python的异常机制提供了非常方便的异常处理方式。

异常机制本质

异常:程序在运行过程中出现的非正常现象
异常处理:程序在出现问题时依然可以正确的执行剩余的程序,而不会因为异常而终止程序执行。

python中内建的异常类

在这里插入图片描述
如,我们尝试一下用5除以0的这个除数异常:

a = 5 / 0

在这里插入图片描述

  • Traceback:追溯,追根溯源
  • most recent call last:最后一次调用
  • ZeroDivisionError:除法中除数为0异常

异常解决的关键:定位
 学会找到异常出现的真正位置,找因果关系
比如:出现以下错误

def a():
    num = 1 / 0

def b():
    a()

def c():
    b()

c()

在这里插入图片描述

try-except结构

语法结构:
try:
 被监控的可能引发异常的语句块

except BaseException [as e]:# 或者直接Exception也可以
 异常处理语句块

遇到异常会直接跳过异常语句以及之后的语句段,直接跳到相应except块中去执行处理异常语句
如:

# try-except
try:
    print('s1')
    print(5/0)
    print('s2')
except ZeroDivisionError as e:
    print('s3')
    print('异常对象:',e) # 产生的异常对象
    print(type(e))
    print("You can't divide by zero!")

print('s4')

在这里插入图片描述
【测试】

# 循环输入数字,如果不是数字则处理异常,直到输入88,则结束循环
while True:
    try:
        x = int(input("Please input a number:"))
        print("输入的数字为:",x)
        if x == 88:
            print("退出程序!")
            break
    except BaseException as e:
        print("异常!输入的不是一个数字!")

print("循环数字输入结束!")

在这里插入图片描述

try…多个except结构

在工作中,其实可以尽量多的去捕获异常(按照先子类后父类的顺序),可以在最后增加BaseException,从上到下,从子类到父类
语法结构:
try:
 被监控的、可能引发异常的语句块
except Exception1:
 处理Exception1的语句块
except Exception2:
 处理Exception2的语句块

except BaseException:
 处理可能遗漏的异常语句块

【测试】

try:
    a = input('Please input a dividend:') # 被除数
    b = input('Please input a divisor:') # 除数
    c = float(a) / float(b)
    print(c)
except ZeroDivisionError:
    print('异常,不能除以0!')
except ValueError:
    print('异常,不能将字符串转化成数字!')
except NameError:
    print('异常,变量不存在!')
except BaseException as e:
    print(e)

在这里插入图片描述
在这里插入图片描述

【注】可以通过鼠标选中异常类右键选择’Diagram‘–‘show Diagram’查看异常类的继承关系图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

try-except-else结构

【测试】

# try-except-else语句
print("Give me two numbers, and I'll divide them.")
print("Enter 'q' to quit.")

while True:
    first_number = input("\nFirst number:")
    if first_number == 'q':
        break
    second_number = input("Second number:")
    if second_number == 'q':
        break
    try:
        answer = int(first_number) / int(second_number)
    except ZeroDivisionError:
        print("You can't divide by 0!")
    else:
        print(answer)

在这里插入图片描述

try-except-finally结构

finally块:无论是否发生异常,都会执行里面的语句,通常用来释放try块中申请的资源
【测试1】

try:
    a = input('Please input a dividend:') # 被除数
    b = input('Please input a divisor:') # 除数
    c = float(a) / float(b)
except BaseException as e:
    print(e)
else:
    print(c)
finally:
    print('无论异常发生与否都会执行finally语句!')

print('程序结束!')

在这里插入图片描述
在这里插入图片描述
【测试2】

try:
    f = open('d:/a.txt','r')
    content = f.readline()
    print(content)
except:
    print('文件未找到!')
finally:
    print('run in finally!')
    try:
        f.close()
    except BaseException as e:
        print(e)

print('程序执行结束!')

在这里插入图片描述
【注意一点】
我们一般不把return语句放在异常处理结构中,而是放到方法的最后
如:

def test01():
    print('s1')
    try:
        x = 3 / 0
    except:
        print('s2')
        print('异常,除数不能为0!')
    finally:
        print('s4')
    print('s5')
    return 'e'
    # 一般不将return语句放到try、except、else、finally块中,会发生一些意想不到的错误,建议放到方法最后!

print(test01())

常见异常汇总

  • SyntaxError:语法错误
  • NameError:尝试访问一个没有声明的变量
  • ZeroDivisionError:除数为0错误
  • ValueError:数值错误
  • TypeError:类型错误
  • AttributeError:访问对象的不存在的属性
  • IndexError:索引越界异常
  • KeyError:字典的关键字不存在

异常表格汇总

异常名称说明
ArithmeticError所有数值计算错误的基类
AssertionError断言语句失败
AttributeError对象没有这个属性
BaseException所有异常的基类
DeprecationWarning关于被弃用的特征的警告
EnvironmentError操作系统错误的基类
EOFError没有内建输入,到达EOF标记
Exception常规错误的基类
FloatingPointError浮点计算错误
FutureWarning关于构造将来语义会有改变的警告
GeneratorExit生成器发生异常来通知退出
ImportError导入模块 / 对象失败
IndentationError缩进错误
IndexError序列中没有此索引
IOError输入 / 输出操作失败
KeyboardInterrupt用户中断执行(通常是^C)
KeyError映射中没有这个键
LookupError无效数据查询的基类
MemoryError内存溢出错误
NameError未声明 / 初始化对象(没有属性)
NotImplementedError尚未实现的方法
OSError操作系统错误
OverflowError数值运算超出最大限制
OverflowWarning旧的关于自动提升为长整型long的警告
PendingDeprecationWarning关于特性将会被废弃的警告
ReferenceError弱引用试图访问已经垃圾回收了的对象
RuntimeError一般的运行时错误
RuntimeWarning可疑的运行时行为的警告
StandardError所有内建标准异常的基类
StopIteration迭代器没有更多的值
SyntaxErrorpython语法错误
SyntaxWarning可疑的语法警告
SystemError一般的解释器系统错误
SystemExit解释器请求退出
TabErrorTab和空格混用
TypeError对类型无效的操作
UnboundLocalError访问未初始化的本地变量
UnicodeDecodeErrorUnicode解码时的错误
UnicodeEncodeErrorUnicode编码时的错误
UnicodeErrorUnicode相关的错误
UnicodeTranslateErrorUnicode转换时错误
UserWarning用户代码生成的警告
ValueError传入无效的参数
Warning警告的基类
WindowsError系统调用失败
ZeroDivisionError除(或取模)零(所有数据类型)

traceback模块

用于打印一些异常信息
【测试1】

import traceback
try:
    print('s1')
    num = 3 / 0
except:
    traceback.print_exc()

在这里插入图片描述
【测试2:将异常信息输出到指定文件中】

import traceback
# 将异常信息输出到指定文件中
try:
    print('s2')
    num = 5 / 0
except:
    with open('d:/Python_projects/test_Exception/test11.txt','a') as f:
        traceback.print_exc(file = f)

在这里插入图片描述
在这里插入图片描述

自定义异常类

一般为运行时异常,通常继承Exception或其子类即可(命名一般以Error、Exception为后缀)
自定义异常由raise语句主动抛出

【测试】

class AgeError(Exception): # 继承Exception类
    def __init__(self,errorInfo):
        Exception.__init__(self)
        self.errorInfo = errorInfo
    def __str__(self):
        return str(self.errorInfo) + '年龄错误!应在1~100之间'

if __name__ == '__main__': # 如果为True,则模块是作为独立文件运行,可以执行测试代码
    age = int(input('Please input an age:'))
    if age < 1 or age > 100:
        raise AgeError(age) # 抛出自定义异常
    else:
        print("正常的年龄!",age)

在这里插入图片描述

文件

文本文件和二进制文件

  • 文本文件:存储的是普通“字符”文本,默认Unicode字符集(两个字节表示一个字符-65536)
  • 二进制文件:存储的是“字节”,必须使用专用软件去解码(如,word文档,照片查看器等)

文件操作相关模块

在这里插入图片描述

创建文件对象open()

语法格式:
变量名 = open(文件名 [,打开方式])

打开方式:
在这里插入图片描述
【注】

  • 如果打开方式中没有增加模式“b”,则默认创建文本文件对象,处理的基本单元为“字符”
  • 如果是二进制模式“b”,则创建的是二进制文件对象,处理的基本单元是“字节”

文本文件的写入

创建文件对象–写入数据–关闭文件对象

f = open(r'plp.txt','a') # a--追加
s = 'ashgffk\neer\n'
f.write(s)
f.close()

在这里插入图片描述
【注】写入中文的时候注意会出现乱码

中文乱码问题

常用的编码介绍:
在这里插入图片描述
一般项目都会使用 UTF-8。unicode 中虽然汉字是两个字节,UTF-8 中汉字是 3 个字节。但是互联网中一个网页也包含了大量的英文字母,这些英文字母只占用 1 个字节,整体占用空间,UTF-8 仍然由于 Unicode。

windows 操作系统默认的编码是 GBK,Linux 操作系统默认的编码是 UTF-8。当我们用 open()时,调用的是操作系统打开的文件,默认的编码是 GBK。

如:

f = open(r'plp.txt','a')
s = '你们好我很喜欢编程\n真的\n'
f.write(s)
f.close()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

close()关闭文件流

借助异常机制,使得文件能够正常关闭

try:
    f = open(r"aa.txt","a")
    str = "ggg"
    f.write(str)
except BaseException as e:
    print(e)
finally:
    f.close()

【小补充】with上下文管理

结合上面的异常处理,由于异常处理中finally块异常如何怎么都会执行,释放资源。另一种方法,我们还可以用with上下文更方便实现释放文件资源的操作,不用再手动关闭文件了

语法结构:
with context_expr [as var]:
 语句块

with代码执行完后,自动会还原原来的现场或上下文,不论是否有异常,总能保证资源正常释放,极大简化工作。
【测试1】

with open('d:/Python_projects/test_Exception/test11.txt','r') as f:
    content = f.readline()
    print(content)
print('程序结束!')

在这里插入图片描述
【测试2】

file_name = 'programming.txt'

with open(file_name,'w') as file_object:
    file_object.write("I love learning Python and programming!\n")

with open(file_name,'a') as file_object:
    file_object.write("I will try my best!\n")
    file_object.write("Hey boy!\n")
    file_object.write("Welcome this world!\n")

with open(file_name,'r') as file_object:
    for line in file_object:
        print(line)

在这里插入图片描述

文本文件的读取

  1. read([size]):从中读取size个字符返回,如果没有,默认读取整个文件内容
  2. readline():读取一行作为结果返回,读到文件末尾,返回空字符串
  3. readlines():文本文件中,每一行作为一个字符串存入列表中,返回该列表

【测试】

with open('pi_digits.txt') as file_object:
    contents = file_object.read()
    print(contents.rstrip()) # rstrip 去除字符串末尾的空白
    print("output ...")

print('\n*******************\n')

file_path = r'D:\test_file\data_set.txt' # 原始路径 前面必须加r(在单引号前面)
with open(file_path,encoding='utf-8') as file_object: # 注意文本文档的编码
    c = file_object.read()
    print(c)

print('\n*********按行读取一个文件**********\n')

with open(r'programming.txt','r') as f:
    while True:
        fragment = f.readline()
        if not fragment:
            break
        else:
            print(fragment, end = "")

print('\n*********使用迭代器(每次返回一行)读取文本文件**********\n')

# 逐行读取
file_path = r'D:\test_file\app_set.txt'
file_name = 'app_set.txt'
with open(file_path,encoding='utf-8') as file_object:
    for line in file_object:
        print(line,end = "")

print('\n********包含文件各行内容的列表***********\n')

# 包含文件各行内容的列表
file_name = 'pi_digits.txt'
with open(file_name) as file_object:
    lines = file_object.readlines()
for line in lines:
    print(line.rstrip())

print(lines) # 列表

print('\n*******************\n')

file_name = 'plp.txt'
with open(file_name) as file_object:
    lines = file_object.readlines()
pi_string = ''
for line in lines:
    pi_string += line.strip() # strip 删除位于左边空格

print(pi_string)
print(len(pi_string))

在这里插入图片描述
在这里插入图片描述
【小练习:给文件每行内容加行号】
文件programming.txt
在这里插入图片描述
【测试enumerate】:枚举 和索引关联起来

# enumerate测试
a = ['我我我','你你你\n','她她它\n']
b = enumerate(a) # 枚举 和索引关联起来
print(a)
print(list(b))

在这里插入图片描述

# 给文件每行内容加行号
with open(r'programming.txt','r',encoding = 'utf-8') as f:
    lines = f.readlines()
    lines = [line.rstrip() + " #" + str(index+1) + '\n' for index,line in enumerate(lines)]

with open(r'programming.txt','w',encoding = 'utf-8') as f:
    f.writelines(lines)

在这里插入图片描述

二进制文件的读取和写入

f = open(r"文件路径及文件名",'wb') # 可写的、重写模式的二进制文件对象
f = open(r"文件路径及文件名",'ab') # 可写的、追加模式的二进制文件对象
f = open(r"文件路径及文件名",'rb') # 可读的二进制文件对象

【例】

with open('boy.jpg','rb') as f:
    with open('boy_copy.jpg','wb') as w:
        for line in f.readlines():
            w.write(line)

print("图片拷贝完成......")

文件对象的常用属性和方法

【总结表格】

1.文件对象的属性:

属性说明
name返回文件的名字
mode返回文件的打开模式
closed若文件被关闭则返回True

2.文件对象的打开模式:

模式说明
r读模式
w写模式
a追加模式
b二进制模式(可与其他模式组合)
+读写模式(可与其他模式组合)

3.文件对象的常用方法:

方法名说明
read([size])从文件中读取size个字节或字符的内容返回,默认读取到文件末尾
readline()从文本文件中读取一行内容
readlines()把文本文件中每一行都作为独立的字符串对象,并将这些对象放入列表返回
write(str)将字符串str内容写入文件
writelines(s)将字符串列表s写入文件,不添加换行符
seek(offset [,whence])把文件指针移动到新的位置
tell()返回文件指针的当前位置
truncate([size])不论指针在什么位置,只留下指针前size个字节的内容,其余全部删除;如果没有传入size,则把指针当前位置一直到文件末尾的内容全部删除
flush()把缓冲区的内容写入文件,但不关闭文件
close()把缓冲区内容写入文件,同时关闭文件,释放文件对象相关资源

【注】
seek(offset [,whence])方法:把文件指针移动到新的位置

  • offset:
    为正:往文件内容结束方向移动
    为负:往文件内容开始方向移动
  • whence:
    0:从文件头开始计算(默认)
    1:从当前位置开始计算
    2:从文件尾开始计算

【测试:文件指针与seek方法】
【查看文件指针的初始位置】

with open('programming.txt','r',encoding = 'utf-8') as f:
    print('文件名:{0}'.format(f.name))
    print(f.tell())

在这里插入图片描述
【读取了一行后,文件指针的当前位置】
在这里插入图片描述
【文件指针偏移】
在这里插入图片描述

pickle序列化

Python中,一切都是对象,也就是一个“存储数据的内存块”。
我们想要将这些“内存块的数据”保存到硬盘上,或通过网络传输到其他计算机上。(通过转化成一系列的串(0101011…)进行传输(序列化),再拿出来还原回对象进行访问(反序列化))
使用pickle实现序列化和反序列操作

使用:

  • pickle.dump(obj , file):将对象obj持久化地存到文件file中
    obj:要被序列化的对象
    file:存储的文件
  • pickle.load(file)
    从file读取数据,反序列化成对象

【例】

import pickle
a1 = 'Stefan'
a2 = 1996
a3 = [20,30,40]
with open(r'data.dat','wb') as f:
    pickle.dump(a1,f)
    pickle.dump(a2,f)
    pickle.dump(a3,f)

with open(r'data.dat','rb') as f:
    b1 = pickle.load(f)
    b2 = pickle.load(f)
    b3 = pickle.load(f)
    print(b1);print(b2);print(b3)

    print(id(a1))
    print(id(b1))

在这里插入图片描述

CSV文件的操作

CSV文件(Comma Separated Values),逗号分隔符文本格式,常用于数据交换、Excel文件、数据库数据的导入导出等等工作。

和Excel文件相比,CSV文件:

  1. 值没有类型,所有值均为字符串
  2. 不能指定字体颜色等样式
  3. 不能指定单元格宽高,不能合并单元格
  4. 没有多个工作表
  5. 不能嵌入图像图表

Python标准库提供csv模块读取和写入csv文件
如,建立一个excel文件
在这里插入图片描述
保存为csv文件,并用记事本打开
在这里插入图片描述
【测试】

import csv

# csv文件的读取
with open('sal.csv','r') as f:
    a_csv = csv.reader(f)
    print(list(a_csv))
    print('--------------------')
    f.seek(0) # 注意这里要把文件指针移回开头,否则只会遍历一次
    for row in a_csv:
        print(row)

# csv文件的写入
with open('mess.csv','w') as f:
    b_csv = csv.writer(f)
    b_csv.writerow(['Number','Name','Age'])
    b_csv.writerow(['1001','Kate',19])

    c = [['1011','Tim',22],['1200','Kate',30]]
    b_csv.writerows(c)

读取结果:
在这里插入图片描述
写入结果:
在这里插入图片描述

os和os.path模块

直接对操作系统进行操作,调用os的可执行文件、命令等,系统运维的核心基础。

os调用文件和命令

os.system:直接调用系统命令(电脑上的程序)
如,
直接调用记事本程序:
在这里插入图片描述
调用注册表regedit:
在这里插入图片描述
查看网络交互情况:
在这里插入图片描述

直接调用可执行文件

import os
 # 直接调用可执行文件 比如,网易云音乐
 os.startfile(r'D:\Software_Install\Cloudmusic\CloudMusic\cloudmusic.exe')

在这里插入图片描述

os模块-文件和目录操作

【常用方法总结】
【操作文件】

【操作目录】
在这里插入图片描述
【例】

#coding=utf-8
import os
# 获取文件和文件夹相关信息
print(os.name) # windows——>nt;Linux和unix——>posix
print(os.sep) # windows——>反斜杠;Linux和unix——>正斜杠
print(repr(os.linesep)) # windows——>\r\n;Linux和unix——>\n
print(os.stat('test_os_01.py')) # 访问文件信息

# 关于工作目录的操作
print(os.getcwd()) # 查看当前工作空间
# os.chdir('d:') # 改变当前的工作目录
# os.mkdir('书籍') # 创建工作目录


# 创建目录、创建多级目录、删除
# os.mkdir('书籍') # 创建目录
# os.rmdir('书籍') # 删除目录(相对于当前工作空间下)
# os.makedirs('Movies/America/Agent Carter') # 创建多级目录
# os.removedirs('Movies/America/Agent Carter') # 注:只能删除空目录!!
# os.makedirs('../音乐/大陆/毛不易') # ../:指的是上级目录
# os.rename('Movies','M') # 重命名
# dirs = os.listdir('Movies')
# print(dirs) # 输出所有的子目录(注:只能获取一级子目录!!)

在这里插入图片描述
【小点】repr()函数:
将对象转化为供解释器读取的形式,也就是说,把一个对象(obj)转换成一个可打印的字符串,它特点是对于包含着转义字符的字符串,也能完整打印出来。

os.path模块

在这里插入图片描述
【测试】

#coding=utf-8
import os
import os.path
from os import path

print('\n****路径判断****\n')
print('是否是绝对路径:{0}'.format(path.isabs(r'D:\Python_projects\test_file\programming.txt')))
print('是否是目录:{0}'.format(path.isdir(r'D:\Python_projects\test_file\programming.txt')))
print('是否是文件:{0}'.format(path.isfile(r'D:\Python_projects\test_file\programming.txt')))
print('文件是否存在:{0}'.format(path.exists(r'D:\Python_projects\test_file\programming.txt')))

print('\n****获得文件基本信息****\n')
print('文件大小:{0}字节'.format(path.getsize(r'D:\Python_projects\test_file\programming.txt')))
print('绝对路径:{0}'.format(path.abspath(r'D:\Python_projects\test_file\programming.txt')))
print('目录的路径:{0}'.format(path.dirname(r'D:\Python_projects\test_file\programming.txt')))

print('\n****获得时间信息****\n') # 距离Unix时间点过了多少毫秒
print(path.getctime(r'D:\Python_projects\test_file\programming.txt')) # 文件创建时间
print(path.getatime(r'D:\Python_projects\test_file\programming.txt')) # 文件最后访问时间
print(path.getmtime(r'D:\Python_projects\test_file\programming.txt')) # 文件最后修改时间

print('\n****对路径的操作****\n')
p = path.abspath(r'D:\Python_projects\test_file\programming.txt')
print(path.split(p)) # 路径切分
print(path.splitext(p)) # 按“.”切分(分割扩展名)
print(path.join('aa','bb','cc')) # 连接多个路径

在这里插入图片描述
【练习:列出工作目录下所有的.py文件,并输出文件名】

#coding=utf-8
# 列出工作目录下所有的.py文件,并输出文件名
import os
path = os.getcwd()
file_list = os.listdir(path)
for filename in file_list:
    if filename.endswith('py'):
        print(filename)

print('\n****用推导式方法****\n')
file_list2 = [filename for filename in os.listdir(path) if filename.endswith('py')]
for f in file_list2:
    print(f)

在这里插入图片描述

walk()递归遍历所有文件和目录

os.walk()方法:
返回一个3个元素的元组,(dirpath,dirnames,filenames)

  • dirpath:指定目录的路径
  • dirnames:目录下所有文件夹
  • filenames:目录下的所有文件

【例】

#coding=utf-8
import os

os.chdir(r'D:\人工智能\专业相关')
path = os.getcwd()
list_files = os.walk(path)

for dirpath,dirnames,filenames in list_files:
    for dir in dirnames:
        print(os.path.join(dirpath,dir))
    for file in filenames:
        print(os.path.join(dirpath,file))

在这里插入图片描述

shutil模块(拷贝和压缩)

  • shutil 模块是 python 标准库中提供的,主要用来做文件和文件夹的拷贝、移动、删除等;还可以做文件和文件夹的压缩、解压缩操作。
  • os 模块提供了对目录或文件的一般操作。shutil 模块作为补充,提供了移动、复制、压缩、解压等操作,这些 os 模块都没有提供。

【测试】

#coding=utf-8
import shutil
import zipfile

# 拷贝
shutil.copyfile('1.txt','1_copy.txt')
shutil.copytree('movie/America','电影') # 注:当文件已存在时,无法创建该文件
shutil.copytree('movie/America','电影',ignore = shutil.ignore_patterns('*.txt','*.html')) # 拷贝时可以选择性忽略一些类型的文件进行拷贝

# 压缩、解压缩
# shutil.make_archive('压缩包所在位置及名字','压缩格式(一般zip)','压缩的目录内容')
shutil.make_archive('音乐/movie','zip','电影/学习')

# 压缩
z1 = zipfile.ZipFile('a.zip','w')
z1.write('1.txt')
z1.write('1_copy.txt')
z1.close()

# 解压缩
z2 = zipfile.ZipFile('d:/a.zip'.'r')
z2.extractall('电影') # 设置解压位置
z2.close()

【练习】用递归算法打印目录的树结构

#coding=utf-8
import os

allfiles = []
def getAllFiles(path,level):
    childFiles = os.listdir(path)
    for file in childFiles:
        filepath = os.path.join(path,file)
        if os.path.isdir(filepath): # 如果目录下还有目录,就递归调用自己,直到文件
            getAllFiles(filepath,level + 1) # 层级结构+1
        allfiles.append('\t' * level + filepath)


getAllFiles(r'D:\人工智能\专业相关',0)

for f in reversed(allfiles):
    print(f)

【测试结果】
在这里插入图片描述

模块

在这里插入图片描述

标准库模块

与函数类似,模块也分为标准库模块和用户自定义模块。
Python 标准库提供了操作系统功能、网络通信、文本处理、文件处理、数学运算等基本的功能。比如:random(随机数)、math(数学运算)、time(时间处理)、file(文件处理)、os(和操作系统交互)、sys(和解释器交互)等。

另外,Python 还提供了海量的第三方模块,使用方式和标准库类似。功能覆盖了我们能想象到的所有领域,比如:科学计算、WEB 开发、大数据、人工智能、图形系统等。

模块化编程(Modular Programming)

  • 模块–Python源代码文件(.py文件)
  • 可将一个python程序根据任务需求分解为多个模块,便于后期的重复应用

模块化编程有如下几个重要优势

  1. 便于将一个任务分解成多个模块,实现团队协同开发,完成大规模程序
  2. 实现代码复用。一个模块实现后,可以被反复调用。
  3. 可维护性增强。

模块化编程的一般流程

  1. 设计 API,进行功能描述。
  2. 编码实现 API 中描述的功能。
  3. 在模块中编写测试代码,并消除全局代码。
  4. 使用私有函数实现不被外部客户端调用的模块函数。

API

API(Application Programming Interface 应用程序编程接口)是用于描述模
块中提供的函数和类的功能描述和使用方式描述。

模块化编程中,首先设计的就是模块的 API(即要实现的功能描述),然后开始编码实现 API 中描述的功能。最后,在其他模块中导入本模块进行调用。我们可以通过help(模块名)查看模块的API。一般使用时先导入模块 然后通过help函数查看。

【help查看】

import math
print(math.sqrt(81))
help(math)

在这里插入图片描述
【Python的API文档中查看】
在这里插入图片描述
在这里插入图片描述
【例】
自己定义一个模块,撰写文档字符串,然后去调用该模块,查看文档字符串等信息

Salary.py文件

#coding=utf-8
'''
用于计算公司员工的薪资
'''

company = 'StarWar'

def yearSalary(monthSalary):
    '''
    根据传入的月薪的值,计算出年薪(monthSalary * 12)
    :param monthSalary: 月薪
    :return: 年薪
    '''
    return monthSalary * 12

def daySalary(monthSalary):
    '''
    根据传入的月薪值,计算日工资,一个月按22.5天计算(国家规定工作日)
    :param monthSalary: 月薪
    :return: 日工资
    '''
    return monthSalary / 22.5

if __name__ == '__main__': # 自己测试用 模块独立运行
    print(yearSalary(4000))
    print(daySalary(4000))

test_Salary.py文件

#coding=utf-8
import Salary
# __doc__获取模块的文档字符串
print(Salary.__doc__)
print(Salary.daySalary.__doc__)
print(Salary.yearSalary.__doc__)
print('模块名:',Salary.__name__)

在这里插入图片描述

模块的导入

import导入

语法格式:
import 模块名  # 导入一个模块
import 模块1,模块2…  # 导入多个模块
import 模块名 as 模块别名   # 导入模块并使用别名

本质:生成了一个对象(module类),并被变量使用。

import 加载的模块分为四个通用类别:

  1. 使用 python 编写的代码(.py 文件)
  2. 已被编译为共享库或 DLL 的 C 或 C++扩展
  3. 包好一组模块的包
  4. 使用 C 编写并链接到 python 解释器的内置模块

【注】

  • 当导入一个模块时, 模块中的代码都会被执行。不过,如果再次导入这个模块,则不会再次执行。(import-only-once)
  • 一个模块无论导入多少次,这个模块在整个解释器进程内有且仅有一个实例对象。
import math as m
print(id(m))
print(type(m))
print(m.sqrt(16))
import math as ma # 无论导入多少次都只生成一个实例对象
print(id(ma))

在这里插入图片描述

from…import导入

可导入模块中的成员(函数 / 类)
如:

#coding=utf-8
from math import sin
print(sin(3.14)) # 可直接写函数名,不用再”.“去调用了

importlib动态导入

import语句的本质:调用内置函数__import __() 实现动态导入,给__import __() 动态传递不同的的参数值,就能导入不同的模块。

使用importlib模块要更好:

#coding=utf-8
import importlib
a = importlib.import_module("math")
b = importlib.import_module("time")
print(a.pi)
print(b.time())

在这里插入图片描述
如需要重新加载模块,用importlib重新加载模块
importlib.reload()方法

包package的使用

基本使用

  • 包必须有__init __.py的文件夹
  • 包下面可以包含模块,也可以包含子包
  • Pycharm中创建包:New–>Python–>package
  • 导入包:
    1.import 一级包名.二级报名.三级… .模块名
    2.from 一级包名.二级包名. … import 模块名
    3.from 一级包名.二级报名.三级… .模块名 import 函数名

【注】
导入包的本质其实是“导入了包的__init__.py”文件。也就是说,”import pack1”意味着执行了包 pack1 下面的__init__.py 文件。 这样,可以在__init__.py 中批量导入我们需要的模块,而不再需要一个个导入。

init.py 的三个核心作用:

  1. 作为包的标识,不能删除。
  2. 用来实现模糊导入
  3. 导入包实质是执行__init__.py 文件,可以在__init__.py 文件中做这个包的初始化、以及需要统一执行代码、批量导入。

包内引用

如果是子包内的引用,可以按相对位置引入子模块 ,比如要引用同工作目录包下你上级目录中的包:

  • from … import module_A  #…表示上级目录 .表示同级目录
  • from . import module_A2  #.表示同级目录

sys.path和模块搜索路径

当我们导入某个模块文件时, Python 解释器去哪里找这个文件呢?只有找到这个文件才能读取、装载运行该模块文件。它一般按照如下路径寻找模块文件(按照顺序寻找,找到即停不继续往下寻找):

  1. 内置模块
  2. 当前目录
  3. 程序的主目录
  4. pythonpath 目录(如果已经设置了 pythonpath 环境变量)
  5. 标准链接库目录
  6. 第三方库目录(site-packages 目录)
  7. .pth 文件的内容(如果存在的话)
  8. sys.path.append()临时添加的目录

当任何一个 python 程序启动时,就将上面这些搜索路径(除内置模块以外的路径)进行收集,放到 sys 模块的 path 属性中(sys.path)。

【测试】

import sys
print(sys.path)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值