文件、异常和模块
参考资料:《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 | 迭代器没有更多的值 |
SyntaxError | python语法错误 |
SyntaxWarning | 可疑的语法警告 |
SystemError | 一般的解释器系统错误 |
SystemExit | 解释器请求退出 |
TabError | Tab和空格混用 |
TypeError | 对类型无效的操作 |
UnboundLocalError | 访问未初始化的本地变量 |
UnicodeDecodeError | Unicode解码时的错误 |
UnicodeEncodeError | Unicode编码时的错误 |
UnicodeError | Unicode相关的错误 |
UnicodeTranslateError | Unicode转换时错误 |
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)
文本文件的读取
- read([size]):从中读取size个字符返回,如果没有,默认读取整个文件内容
- readline():读取一行作为结果返回,读到文件末尾,返回空字符串
- 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文件:
- 值没有类型,所有值均为字符串
- 不能指定字体颜色等样式
- 不能指定单元格宽高,不能合并单元格
- 没有多个工作表
- 不能嵌入图像图表
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程序根据任务需求分解为多个模块,便于后期的重复应用
模块化编程有如下几个重要优势:
- 便于将一个任务分解成多个模块,实现团队协同开发,完成大规模程序
- 实现代码复用。一个模块实现后,可以被反复调用。
- 可维护性增强。
模块化编程的一般流程:
- 设计 API,进行功能描述。
- 编码实现 API 中描述的功能。
- 在模块中编写测试代码,并消除全局代码。
- 使用私有函数实现不被外部客户端调用的模块函数。
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 加载的模块分为四个通用类别:
- 使用 python 编写的代码(.py 文件)
- 已被编译为共享库或 DLL 的 C 或 C++扩展
- 包好一组模块的包
- 使用 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 的三个核心作用:
- 作为包的标识,不能删除。
- 用来实现模糊导入
- 导入包实质是执行__init__.py 文件,可以在__init__.py 文件中做这个包的初始化、以及需要统一执行代码、批量导入。
包内引用
如果是子包内的引用,可以按相对位置引入子模块 ,比如要引用同工作目录包下你上级目录中的包:
- from … import module_A #…表示上级目录 .表示同级目录
- from . import module_A2 #.表示同级目录
sys.path和模块搜索路径
当我们导入某个模块文件时, Python 解释器去哪里找这个文件呢?只有找到这个文件才能读取、装载运行该模块文件。它一般按照如下路径寻找模块文件(按照顺序寻找,找到即停不继续往下寻找):
- 内置模块
- 当前目录
- 程序的主目录
- pythonpath 目录(如果已经设置了 pythonpath 环境变量)
- 标准链接库目录
- 第三方库目录(site-packages 目录)
- .pth 文件的内容(如果存在的话)
- sys.path.append()临时添加的目录
当任何一个 python 程序启动时,就将上面这些搜索路径(除内置模块以外的路径)进行收集,放到 sys 模块的 path 属性中(sys.path)。
【测试】
import sys
print(sys.path)