Python之模块
-
模块
- Python模块(Module),本质就是一个Python文件,以
.py
结尾,包含了Python对象定义和Python语句,是封装语句的最小单位。一个模块就是就是包含了一组功能的Python文件,比如spam.py
,模块名为spam
,可以通过import spam
调用模块。模块不宜过大,不便于维护。
- Python模块(Module),本质就是一个Python文件,以
-
模块的分类
在Python中,模块的使用方法都是一样的,可以细分为四个通用类别:
- 使用Python编写的
.py
文件 - 已被编译为共享库或DLL的C或C++扩展
- 把一系列模块组织到一起的文件夹(注:该文件夹下有一个
__init__.py
文件,该文件夹称之为包,导入一个包相当于执行了这个包下的__init__.py
文件,并不是把这个包下的所有文件都导入进来) - 使用C语言编写,并链接到Python解释器的内置模块
- 使用Python编写的
-
使用模块的意义
- 模块让你能够有逻辑地组织你的 Python 代码段;把相关的代码分配到一个模块里能让你的代码更好用,更易懂;模块能定义函数,类和变量,模块里也能包含可执行的代码;拿来主义,提升开发效率。
-
自定义模块
-
本质就是创建一个Python文件。自定义模块开头应注释说明自定义模块的作用,以下是
time
模块的注释说明# encoding: utf-8 # module time # from (built-in) # by generator 1.147 """ This module provides various functions to manipulate time values. There are two standard representations of time. One is the number of seconds since the Epoch, in UTC (a.k.a. GMT). It may be an integer or a floating point number (to represent fractions of seconds). The Epoch is system-defined; on Unix, it is generally January 1st, 1970. The actual value can be retrieved by calling gmtime(0). The other representation is a tuple of 9 integers giving local time. The tuple items are: year (including century, e.g. 1998) month (1-12) day (1-31) hours (0-23) minutes (0-59) seconds (0-59) weekday (0-6, Monday is 0) Julian day (day in the year, 1-366) DST (Daylight Savings Time) flag (-1, 0 or 1) If the DST flag is 0, the time is given in the regular time zone; if it is 1, the time is given in the DST time zone; if it is -1, mktime() should guess based on the date and time. """ # no imports # Variables with simple values
-
自定义模块中出现的变量、可执行语句、函数定义等称之为模块的成员。
-
-
模块的运行方式
-
脚本方式:直接使用解释器执行,或PyCharm等软件中直接运行
-
模块方式:被其他模块导入执行,为导入它的模块提供资源(变量、函数定义和类定义等)。当自定义模块被其它模块导入时,其中的可执行语句会立即执行。在Python中,
__name__
是属于 python 中的内置类属性,代表对应程序名称。当模块以脚本方式运行时,__name__
等于__main__
,当模块以导入方式运行时,__name__
等于模块的名字。通过这一特性可以解决模块被导入方式运行时,可执行语句会立即执行的问题。# 在自定义模块中,通常可执行程序放在下面这条判断语句之下,而成员定义放在这条判断语句之上。 user = 'Python' def func_1(): pass def func_2(): pass # 通常会将所有可执行的语句放在一个测试函数内,在开发阶段调用这个函数执行本模块功能测试 def main(): func_1() func_2() if __name__ == '__main__': # 在Pycharm中输入main按回车可以快速生成 main()
-
-
系统导入模块的路径
-
内存中:如果成功导入过模块,直接使用已经存在的模块。
-
内置路径中:Python解释器安装路径下的Lib文件夹。
-
sys.path:是一个路径列表,可以动态修改。
import sys print(sys.path) # 如果自定义模块与调用模块不在同一路径下,需要将自定义模块的路径添加到sys.path中 # 将路径添加到sys.path中 sys.path.append(r'自定义模块的绝对路径') # 使用os模块获取一个路径的父路径 import os os.path.dirname(__file__) + r'自定义模块所在的文件夹' # __file__ 获取当前文件的绝对路径 # 因此,将一个模块的路径添加到sys.path中可以这样写
sys.path.append(os.path.dirname(file + '自定义模块所在的文件夹'))
```
-
-
模块的导入方式
-
方式1:导入模块的所有成员,调用成员时必须使用
模块名称.成员名称
的方式import 模块名称
- 首次导入模块发生的三件事:
- 创建一个模块的名称空间;
- 执行模块对应文件,将产生的名字存放于创建的名称空间中;
- 在当前执行文件中拿到一个模块名,该模块名指向创建的名称空间。
- 注意:多次调用模块只会引用第一次调用时导入的结果,不会重复执行模块;且实行模块中的功能,始终以模块的名称空间为准。
- 首次导入模块发生的三件事:
-
方式2:一次性导入多个模块的成员
import 模块名称1,模块名称2,模块名称3,…… # 不建议这么写,最好分开写
-
方式3:从一个模块中导入某个成员
from 模块名称 import 成员名称 # 好处是节省内存空间
- 首次导入模块发生的三件事:
- 创建一个模块的名称空间;
- 执行模块对应文件,将产生的名字存放于创建的名称空间中;
- 在当前名称空间中直接拿到模块中的名字,可以直接使用,不用加任何模块名前缀。
- 注意:多次调用模块只会引用第一次调用时导入的结果,不会重复执行模块;且实行模块中的功能,始终以模块的名称空间为准。此方式有可能与当前名称空间的名字冲突。
- 区别:
-
import 模块名
的方式调用模块时,需要以模块名.模块中功能或方法的名字
使用。 -
from 模块名 import 模块中功能的名字
的方式调用模块时,直接用模块中功能或方法的名字
使用。
-
-
方式4:从一个模块中导入多个个成员
from 模块名称 import 成员名称1,成员名称2,成员名称3
-
方式5:从一个模块中导入所有成员,调用时直接使用
成员名称
,但容易导致命名冲突from 模块名称 import *
-
方式6:使用别名alias(缩写为:as)避免命名冲突
# 为模块起别名 import 模块名称1 as 模块名称2 # 为成员起别名 from 模块名称 import 成员名称1 as 成员名称2
-
方式7:控制
from 模块名称 import *
成员的导入__all__
是一个列表,用于表示本模块可以被外界使用的成员。元素是成员名字的字符串。此方式只针对from 模块名称 import *
的导入方式生效。__all__ = ['a', 'b', 'c'] a = 1 b = 2 c = 3 # 成员d不会被导入 d = 4
-
方式8:相对导入。针对一个项目中的不同模块间的导入(可以在不同的文件夹下),称之为相对导入。主要用于隐藏同项目中导入的其他模块。
''' 文件结构: d d_1 d_1_f.py d_2 d_2_f1.py d_2_f2.py ''' # 如果d_2_f1.py需要相对导入d_2_f2.py from . import d_2_f2.py # 如果d_1_f.py作为项目入口,需要调用d_2_f1.py # .表示相对路径 # ..表示父路径 # ...表示父路径的父路径 from .. d_2.d_2_f1 import *
-
-
常用模块
-
random
模块:提供了获取伪随机数相关的方法-
random.random()
:获取一个[0,1)
范围内的随机浮点数。 -
random.randint(a, b)
:获取一个[a, b]
范围内的随机整数。 -
random.uniform(a, b)
:获取一个[a, b]
范围内的随机浮点数。 -
random.shuffle(x)
:将x中的元素顺序随机打乱,参数x必须是一个可变数据类型。 -
random.sample(x, k)
:从x中随机抽取k个数据,组成一个列表返回。
-
-
time
模块:提供了获取时间戳相关的方法-
time.time()
:获取当前的时间戳(从计算机元年1970年1月1日0点0分0秒到现在经过的秒数)。 -
time.gmtime()
:获取GMT格式化时间对象,默认参数为当前时间戳。 -
time.localtime()
:获取本地格式化时间对象,默认参数为当前时间戳。 -
time.mktime()
格式化时间对象转换成时间戳。import time print(time.mktime(time.localtime()))
-
time.strftime()
:格式化时间对象转换成字符串,默认参数为当前时间戳。import time print(time.strftime('%Y-%m-%d %H:%M:%S')) # 2020-02-18 22:18:58
-
time.strptime()
:字符串转换成格式化时间对象。import time print(time.strptime('2020-02-18 22:18:58','%Y-%m-%d %H:%M:%S')) # 输出结果:time.struct_time(tm_year=2020, tm_mon=2, tm_mday=18, tm_hour=22, tm_min=18, tm_sec=58, tm_wday=1, tm_yday=49, tm_isdst=-1)
-
time.sleep(secs)
:暂停当前线程,睡眠secs
秒
-
-
datetime
模块:日期时间模块。封装了和日期、时间相关的类,主要用于数学计算。-
datetime
中的date
类:格式化输出:年-月-日import datetime d = datetime.date(2020,1,1) print(d) # 2020-01-01 print(d.year) # 获取date对象的year属性:2010 print(d.month) # 获取date对象的month属性:1 print(d.day) # # 获取date对象的day属性:1
-
datetime
中的time
类:格式化输出:时:分:秒import datetime t = datetime.time(10,59,59) print(t) # 10:59:59 print(t.hour) # 获取time对象的hour属性:10 print(t.minute) # 获取time对象的miute属性:59 print(t.second) # 获取time对象的second属性:59
-
datetime中的datetime类:格式化输出:年-月-日 时:分:秒
import datetime dt = datetime.datetime(2020,1,1,10,59,59) print(dt) print(dt.year) print(dt.month) print(dt.day) print(dt.hour) print(dt.minute) print(dt.second)
-
datetime
中的timedelta
类:输出时间的变化量,用于时间的运算,运算的结果类型和操作数保持一致。import datetime dt = datetime.timedelta(days=1) print(dt) # 1 day, 0:00:00 d = datetime.date(2020,1,1) res = d + dt print(res) # 2020-01-02 # 根据用户输入的年份判断是否是闰年,闰年2月有29天,平年2月有28天 # 计算方法:使用datetime模块,首先创建指定的年份的3月1日,往前走一天 import datetime while 1: year = input('请输入年份:').strip() year = int(year) # 将用户输入的字符串类型转换成整数类型 d = datetime.date(year,3,1) td = datetime.timedelta(days=1) res = d - td if res.day == 29: print(f'{year}年是闰年!') else: print(f'{year}年是平年。')
注意:只有
date
、datetime
、timedelta
类才能与timedelta
类之间可以进行运算,并且会产生进位;而time
类不能与timedelta
类进行运算。
-
-
os
模块:提供了文件操作的常用方法。(自动化运维常用的模块为shutil
)-
os.remove()
:删除文件 -
os.rename()
:修改文件名称 -
os.removedirs()
:删除空目录,只能删除空目录。 -
os.path
:path模块是os模块的子模块,封装了很多文件路径的操作方法。 -
os.system('command')
:执行系统的command命令
-
-
sys
模块:提供了和Python解释器相关的操作。-
sys.argv
:在程序中获取Python文件通过命令行运行后时后面的参数,sys.argv[0]
获取的是文件名,sys.argv[1]
获取文件名后的第一个参数,sys.argv[2]
获取文件名后的第二个参数。 -
sys.path
:以列表的形式返回解释器寻找模块的路径。 -
sys.modules
:以字典的形式返回系统已经加载的模块。
-
-
json
模块:将数据转换成字符串,用于数据存储和传输。结构化数据不能直接写入文件,只有非结构化的线性数据才可以。json
已经成为一种简单通用的数据交换格式(可以跨语言数据交互)。-
序列化 (Serialization):将内存中的数据,转换成字节,用以保存在文件或通过网络传输,称之为序列化过程(把数据从内存中拿出去)。可
json
序列化的数据类型有数值、字符串、列表、元组、字典等,但集合不可被json
序列化,同时,元组被序列化后,会变成列表形式的字符串。-
json.dump(obj, f)
:将指定的对象存储到文件中,从内存到硬盘。import json with open(r'test.txt', mode='wt', encoding='UTF-8') as f: # 注意:以text类型写入 json.dump([1,2,3,4,5],f)
-
json.dumps(obj)
:将指定的对象转换成json格式的字符串,从内存到内存。import json res = json.dumps([1,2,3]) print(res,type(res)) # [1, 2, 3] <class 'str'> # json文件通常是一次性写,但通过多次序列化的方式可以实现多次写 import json with open(r'test.txt', mode='at', encoding='UTF-8') as f: f.write(json.dumps([1, 2, 3]) + '\n') f.write(json.dumps([4, 5, 6]) + '\n')
-
-
反序列化 (Deserialization):从文件、网络中获取的数据转换成内存中原来的数据类型,称之为反序列化过程。(把数据拿到内存中)
-
json.load(f)
:将文件中的字符串数据转换成序列化前的数据类型。import json with open(r'test.txt', mode='rt', encoding='UTF-8') as f: b = json.load(f) print(b,type(b)) # [1, 2, 3, 4, 5] <class 'list'>
-
json.loads(s)
:将内存中的字符串数据转换成序列化前的数据类型。import json res = json.dumps([1,2,3]) l = json.loads(res) print(l,type(l)) # [1, 2, 3] <class 'list'> # json文件通常是一次性读,但通过多次反序列化的方式i可以实现多次读 import json with open(r'test.txt', mode='rt', encoding='UTF-8') as f: for i in f: res = json.loads(i.strip('\n'))
-
-
-
pickle
模块:可以将Python中所有的数据类型进行序列化与反序列化的过程,将数据类型与字节相互转换。可以多次对同一个文件进行序列化,但pickle
序列化的数据只能用于Python!-
序列化:相较于
json
模块,pickle
模块序列化的更彻底,直接将数据类型转换成的是字节,而不是字符串。-
pickle.dump:把
pickle
序列化内容从内存写入到硬盘文件。import pickle with open(r'test.txt', mode='wb') as f: # 注意:以bytes类型写入 pickle.dump([1,2,3],f)
-
pickle.dumps:把
pickle
序列化内容从内存写入到内存。import pickle res = pickle.dumps(10) print(res,type(res)) # b'\x80\x04K\n.' <class 'bytes'>
-
-
反序列化:将字节文件转换成序列化前的数据类型。
-
pickle.load:将硬盘文件中的字节写到内存中,并转换成序列化前的数据类型
import pickle with open(r'test.txt', mode='rb') as f: res = pickle.load(f) print(res,type(res)) # [1, 2, 3] <class 'list'>
-
pickle.loads:将内存中的字节写到内存中,并转换成序列化前的数据类型
import pickle res = pickle.dumps(10) l = pickle.loads(res) print(l,type(l)) # 10 <class 'int'>
-
-
-
hashlib
模块:封装一些用于加密的类。加密的目的是用来验证文件,而非解密文件。-
特点:
- 将一个数据切片后,对每片数据进行加密,所有数据片组装后的加密结果与直接对文件加密的结果一致;
- 单向加密不可逆;
- 原始数据的微小变化,将导致加密结果的雪崩式差异;
- 无论文件多大,hash值的长度是固定的。不同加密算法,加密结果的长度不同;
- 只能对字节进行加密。
-
使用:
-
生成一个文件的hash值
import hashlib # 获取一个加密对象 user_file = hashlib.md5() user_file_path = input('请输入您需要验证程序或文件的路径:'.strip()) with open(f'{user_file_path}', mode='rb') as f: # 以binary(二进制)方式读 for line in f: # 使用加密对象的update方法,把值传给md5算法进行加密 user_file.update(line) # 通过hexdigest()方法获取加密结果,返回一个十六进制的字符串 hash_value = user_file.hexdigest() print(f'您程序或文件的hash值为:{hash_value}') # 注意:以下写法的值是一样的 # 写法1 import hashlib m = hashlib.md5(b'abc') print(m.hexdigest()) # 900150983cd24fb0d6963f7d28e17f72 # 写法2 m = hashlib.md5() m.update(b'abc') print(m.hexdigest()) # 900150983cd24fb0d6963f7d28e17f72
-
验证两个文件的hash值是否相同,判断两个文件的原文是否相同。
-
加盐:为了防止黑客通过彩虹表根据哈希值反推原始口令,在计算哈希的时候,不能仅针对原始输入计算,需要增加一个salt来使得相同的输入也能得到不同的哈希,这样,大大增加了黑客破解的难度。如果salt是我们自己随机生成的,通常我们计算MD5时采用md5(message + salt)。但实际上,把salt看做一个“口令”,加salt的哈希就是:计算一段message的哈希时,根据不通口令计算出不同的哈希。要验证哈希值,必须同时提供正确的口令。
import hashlib # 获取一个加密对象 user_file = hashlib.md5(b'salt') # 加盐 user_file_path = input('请输入您需要验证程序或文件的路径:'.strip()) with open(f'{user_file_path}', mode='rb') as f: # 以binary(二进制)方式读 for line in f: # 使用加密对象的update方法,把值传给md5算法进行加密 user_file.update(line) # 通过hexdigest()方法获取加密结果,返回一个十六进制的字符串 hash_value = user_file.hexdigest() print(f'您程序或文件的hash值为:{hash_value}') #4795d80f956d95feab5f1dedc7b51792
-
-
-
hmac
模块:Keyed-Hashing for Message Authentication 它通过一个标准算法,在计算哈希的过程中,把key混入计算过程中。-
与
hashlib
加salt算法不同,hmac算法针对所有哈希算法都通用,无论是MD5还是SHA-1。采用hmac替代我们自己的salt算法,可以使程序算法更标准化,也更安全。Python自带的hmac模块实现了标准的hmac算法。我们来看看如何使用hmac实现带key的哈希。import hmac message = b'Hello, world!' key = b'secret' h = hmac.new(key, message, digestmod='MD5') # 如果消息很长,可以多次调用h.update(msg) h.hexdigest()
-
-
subprocess
模块:Python 2.4 中新增的一个模块,它允许你生成新的进程,连接到它们的 input/output/error 管道,并获取它们的返回(状态)码。这个模块的目的在于替换几个旧的模块和方法,如:os.system,os.spawnimport subprocess obj=subprocess.Popen('yum -y update',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) # shell=True 表示使用解释器解释命令; # stdout=subprocess.PIPE 表示将正确的结果往stdout管道丢; # stderr=subprocess.PIPE 表示将错误的结果往stderr管道丢; # PIPE就是管道的意思 res_stdout=obj.stdout.read() # 通过管道读取正确的结果,而且,结果只能取一次,取走了就没有了 print(res_stdout.decode('utf-8')) res_stderr=obj.stderr.read() # 通过管道读取错误的结果,而且,结果只能取一次,取走了就没有了 print(res_stderr.decode('utf-8'))
-
configparser
模块:该基本配置语言提供的结构类似于Microsoft Windows INI文件中的结构。用于生成和修改常见配置文档。
-
shutil
模块:高级的文件、文件夹、压缩包处理模块。-
拷贝文件:
import shutil shutil.copy2('src', 'dst')
-
拷贝目录:
import shutil shutil.copytree('src', 'dst', ignore=shutil.ignore_patterns('*.mp4')) # ignore=shutil.ignore_patterns('*.mp4')可以指定哪些文件不拷贝,根据自己需求,可以不用写
-
删除目录:
import shutil shutil.rmtree('src', ignore_errors=True)
-
移动文件或目录:
import shutil shutil.move('src', 'dst', copy_function=shutil.copy2)
-
获取磁盘使用空间:
import shutil total, used, free = shutil.disk_usage(r'c:/') print(F'总大小:{total/1024/1024/1024}GB,可使用大小:{used/1024/1024/1024}GB,剩余大小:{free/1024/1024/1024}GB')
-
压缩文件:
import shutil shutil.make_archive('test.txt', 'zip', 'root_dir')
-
解压文件:
import shutil shutil.unpack_archive('filename', 'extract_dir')
-
-
logging
模块:日志模块,一般用来trouble shooting和数据分析。但无论希望日志里打印哪些内容,都得自己写,没有自动生成日志这种事儿。-
导入日志模块
import logging logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')
-
定义日志基本配置
import logging logging.basicConfig( format='%(asctime)s - %(filename)s - [line:%(lineno)d] - %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S', filename='parser_result.log', filemode='a' ) logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')
-
logging.basicConfig
函数各参数:- filename: 指定日志文件名
- filemode: 和file函数意义相同,指定日志文件的打开模式,'w'或'a'
- format: 指定输出的格式和内容,format可以输出很多有用信息,如上例所示:
- %(levelno)s: 打印日志级别的数值
- %(levelname)s: 打印日志级别名称
- %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[]
- %(filename)s: 打印当前执行程序名
- %(funcName)s: 打印日志的当前函数
- %(lineno)d: 打印日志的当前行号
- %(asctime)s: 打印日志的时间
- %(thread)d: 打印线程ID
- %(threadName)s: 打印线程名称
- %(process)d: 打印进程ID
- %(message)s: 打印日志信息
- datefmt: 指定时间格式,同time.strftime()
- level: 设置日志级别,默认为logging.WARNING
- stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略
-
-
网友评论