二十一、常见模块
上一章介绍了Python模块的相关知识,在实际开发中,Python的很多功能都已经有了成熟的第三方实现,一般不需要开发者”重复造轮子“,当开发者需要完成某种功能时,通过搜索引擎进行搜索,通常可以找到第三方在Python中为该功能所提供的扩展模块。实际上,Python语言本身也内置了大量模块,对于常规的日期、时间、正则表达式、JSON支持、容器类等,Python内置的模块已经非常完备。
Python内置模块总是在不断更新中,本文只是起到抛砖引玉的作用
21.1 常用模块
21.1.1 sys模块
sys模块代表了Python解释器,主要用于获取和Python解释器相关的信息。
如下示例,查看sys模块包含的程序单元(包括变量、函数等)。
>>> import sys
>>> [e for e in dir(sys) if not e.startswith('_')]
['addaudithook', 'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix',
'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing', 'copyright',
'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook',
'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style',
'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth', 'getallocatedblocks',
'getdefaultencoding', 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile',
'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace',
'getwindowsversion', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern',
'is_finalizing', 'last_traceback', 'last_type', 'last_value', 'maxsize', 'maxunicode',
'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform',
'platlibdir', 'prefix', 'ps1', 'ps2', 'pycache_prefix', 'set_asyncgen_hooks',
'set_coroutine_origin_tracking_depth', 'setprofile', 'setrecursionlimit',
'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info',
'unraisablehook', 'version', 'version_info', 'warnoptions', 'winver']
>>>
不必记住所有的单元,通常时用到哪些模块就去查阅其对应的说明文档和参考手册。sys模块的参考页面.
大部分时候用不到sys模块里很冷僻的功能,本节只介绍sys模块中常用属性和函数。
- sys.argv : 获取运行Python程序的命令行参数。其中sys.argv[0]通常指该Python程序,sys.argv[1]代表Python程序提供的第一个参数,sys.argv[2]代表第二个参数…以此类推。
- sys.byteorder : 显示本地字节序的指示符。如果本地字节序时大端模式。则该属性返回big;否则返回little。
- sys.copyright : 该属性返回与Python解释器相关的版权信息。
- sys.executable : 该属性返回Python解释器在磁盘上的存储路径。
- sys.flags : 该只读属性返回运行Python命令时指定的旗标。
- sys.getfilesystemencoding() : 返回在当前系统中保存文件所用的字符集。
- sys.getrefcount(object) : 返回指定对象的引用计算。前面介绍过,当object对象的引用计算为0时,系统会回收该对象。
- sys.getrecursionlimit() : 返回Python解释器当前支持的递归深度,该属性可通过setrecursionlimit()方法重置。
- sys.getswitchinterval() : 返回在当前Python解释器中线程切换的时间间隔,该属性可以通过setswitchinterval()函数改变。
- sys.implementation:返回当前Python解释器的实现。
- sys.maxsize: 返回Python整数支持的最大值。在32位平台上,该属性值位231-1;在64位平台上,该属性值为263-1.
- sys.modules : 返回模块名和载入模块对应关系的字典。
- sys.path : 该属性指定Python产找模块的路径列表。程序可通过修改该属性来动态增加Python加载模块的路径。
- sys.platform : 返回Python解释器所在平台的标识符。
- sys.stdin : 返回系统的标准输入流(类文件对象)
- sys.stdout : 返回系统的标准输出流(类文件对象)
- sys.stderr : 返回系统的错误输出流(类文件对象)
- sys.version : 返回当前Python解释器的版本信息。
- sys.winver : 返回当前Python解释器的主版本号。
示例:
>>> import sys
>>> print(sys.argv)
['']
>>> print(sys.copyright)
Copyright (c) 2001-2021 Python Software Foundation.
All Rights Reserved.
Copyright (c) 2000 BeOpen.com.
All Rights Reserved.
Copyright (c) 1995-2001 Corporation for National Research Initiatives.
All Rights Reserved.
Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
All Rights Reserved.
>>> print(sys.executable)
D:\Administrator\05-Personal\Software\python-3.9.9-embed-amd64\python.exe
>>> print(sys.getfilesystemencoding())
utf-8
>>>
21.1.2 os模块
os模块代表了程序所在的操作系统,主要用于获取程序运行所在操作系统的相关信息。
在Python交互解释器中先导入os模块,使用all命令查看该模块对外开放的全部属性和函数。示例如下:
>>> import os
>>> os.__all__
['altsep', 'curdir', 'pardir', 'sep', 'pathsep', 'linesep', 'defpath', 'name', 'path',
'devnull', 'SEEK_SET', 'SEEK_CUR', 'SEEK_END', 'fsencode', 'fsdecode', 'get_exec_path',
'fdopen', 'popen', 'extsep', '_exit', 'DirEntry', 'F_OK', 'O_APPEND', 'O_BINARY',
'O_CREAT', 'O_EXCL', 'O_NOINHERIT', 'O_RANDOM', 'O_RDONLY', 'O_RDWR', 'O_SEQUENTIAL',
'O_SHORT_LIVED', 'O_TEMPORARY', 'O_TEXT', 'O_TRUNC', 'O_WRONLY', 'P_DETACH', 'P_NOWAIT',
'P_NOWAITO', 'P_OVERLAY', 'P_WAIT', 'R_OK', 'TMP_MAX', 'W_OK', 'X_OK', 'abort', 'access',
'chdir', 'chmod', 'close', 'closerange', 'cpu_count', 'device_encoding', 'dup', 'dup2',
'environ', 'error', 'execv', 'execve', 'fspath', 'fstat', 'fsync', 'ftruncate',
'get_handle_inheritable', 'get_inheritable', 'get_terminal_size', 'getcwd', 'getcwdb',
'getlogin', 'getpid', 'getppid', 'isatty', 'kill', 'link', 'listdir', 'lseek', 'lstat',
'mkdir', 'open', 'pipe', 'putenv', 'read', 'readlink', 'remove', 'rename', 'replace',
'rmdir', 'scandir', 'set_handle_inheritable', 'set_inheritable', 'spawnv', 'spawnve',
'startfile', 'stat', 'stat_result', 'statvfs_result', 'strerror', 'symlink', 'system',
'terminal_size', 'times', 'times_result', 'truncate', 'umask', 'uname_result', 'unlink',
'unsetenv', 'urandom', 'utime', 'waitpid', 'waitstatus_to_exitcode', 'write', 'makedirs',
'removedirs', 'renames', 'walk', 'execl', 'execle', 'execlp', 'execlpe', 'execvp',
'execvpe', 'getenv', 'supports_bytes_environ', 'spawnl', 'spawnle']
>>>
同样不需要记住所有的函数,os模块主要包含3方面的内容:
- 系统相关的函数
方法 | 说明 |
os.name | 返回导入依赖模块的操作系统名称,通常可返回’posix’,‘nt’,'java’等值其中之一 |
os.environ | 返回在当前系统上所有环境变量组成的字典 |
os.fsencode(filename) | 该函数对类路径(path-like)的文件名进行编码 |
os.fsdecode(filename) | 该函数对类路径(path-like)的文件名进行解码 |
os.PathLike | 这是一个类,代表一个类路径(path-like)对象 |
os.getenv(Key,default=None) | 获取指定环境变量的值 |
os.getlosin() | 返回当前系统的登录用户名。与该函数对应的还有os.getuid(),os.getgroups(),os.getgid()等函数,用于获取用户ID,用户组,组ID等,这些函数通常只在UNIX系统上有效 |
os.getpid | 获取当前进程ID |
os.getppid | 获取当前进程的父进程ID |
os.putenv(key,value) | 该函数用于设置环境变量 |
os.cpu_count() | 返回当前系统的cpu数量 |
os.sep | 返回路径分隔符 |
os,pathsep | 返回当前系统上多条路径之间的分隔符,一般在Windows系统上多条路径之间的分隔符是英文分号(;);在UNIX及类UNIX系统上多条路径分隔符是英文冒号(:) |
os.linesep | 返回当前系统的换行符。WIndows为’\r\n’;UNIX’为’\n’;Mac OS X为’\r’ |
os.urandom(size) | 返回时和作为加密使用的、最多由N个字节组成的bytes对象。该函数通过操作系统特定的随机性来源返回随机字节,该随机字节通常是不可预测的,因此适用于绝大部分加密场景 |
下面程序演示了表 1 中部分函数的功能和用法:
>>> import os
>>> os.name
'nt'
>>> os.getenv('PYTHONPATH')
>>> os.getlogin()
'F21633C'
>>> os.getpid()
13676
其他的示例就不一一试验了,感兴趣的读者可以自己尝试。
- 文件相关的函数
具体的用法我们还会在后续文件操作中进行介绍。
方法 | 说明 |
os.path.abspath(path) | 返回 path 的绝对路径。 |
os.path.basename(path) | 获取 path 路径的基本名称,即 path 末尾到最后一个斜杠的位置之间的字符串。 |
os.path.commonprefix(list) | 返回 list(多个路径)中,所有 path 共有的最长的路径。 |
os.path.dirname(path) | 返回 path 路径中的目录部分。 |
os.path.exists(path) | 判断 path 对应的文件是否存在,如果存在,返回 True;反之,返回 False。和 lexists() 的区别在于,exists()会自动判断失效的文件链接(类似 Windows 系统中文件的快捷方式),而 lexists() 却不会。 |
os.path.lexists(path) | 判断路径是否存在,如果存在,则返回 True;反之,返回 False。 |
os.path.expanduser(path) | 把 path 中包含的 “~” 和 “~user” 转换成用户目录。 |
os.path.expandvars(path) | 根据环境变量的值替换 path 中包含的 “{name}”。 |
os.path.getatime(path) | 返回 path 所指文件的最近访问时间(浮点型秒数)。 |
os.path.getmtime(path) | 返回文件的最近修改时间(单位为秒)。 |
os.path.getctime(path) | 返回文件的创建时间(单位为秒,自 1970 年 1 月 1 日起(又称 Unix 时间))。 |
os.path.getsize(path) | 返回文件大小,如果文件不存在就返回错误。 |
os.path.isabs(path) | 判断是否为绝对路径。 |
os.path.isfile(path) | 判断路径是否为文件。 |
os.path.isdir(path) | 判断路径是否为目录。 |
os.path.islink(path) | 判断路径是否为链接文件(类似 Windows 系统中的快捷方式)。 |
os.path.ismount(path) | 判断路径是否为挂载点。 |
os.path.join(path1[, path2[, …]]) | 把目录和文件名合成一个路径。 |
os.path.normcase(path) | 转换 path 的大小写和斜杠。 |
os.path.normpath(path) | 规范 path 字符串形式。 |
os.path.realpath(path) | 返回 path 的真实路径。 |
os.path.relpath(path[, start]) | 从 start 开始计算相对路径。 |
os.path.samefile(path1, path2) | 判断目录或文件是否相同。 |
os.path.sameopenfile(fp1, fp2) | 判断 fp1 和 fp2 是否指向同一文件。 |
os.path.samestat(stat1, stat2) | 判断 stat1 和 stat2 是否指向同一个文件。 |
os.path.split(path) | 把路径分割成 dirname 和 basename,返回一个元组。 |
os.path.splitdrive(path) | 一般用在 windows 下,返回驱动器名和路径组成的元组。 |
os.path.splitext(path) | 分割路径,返回路径名和文件扩展名的元组。 |
os.path.splitunc(path) | 把路径分割为加载点与文件。 |
os.path.walk(path, visit, arg) | 遍历path,进入每个目录都调用 visit 函数,visit 函数必须有 3 个参数(arg, dirname, names),dirname 表示当前目录的目录名,names 代表当前目录下的所有文件名,args 则为 walk 的第三个参数。 |
os.path.supports_unicode_filenames | 设置是否可以将任意 Unicode 字符串用作文件名。 |
- 进程管理函数
主要用于启动新进程、中止已有进程等
方法 | 说明 |
os.abort() | 生成一个SIGABRT(硬件异常终止)信号给当前进程。在UNIX系统上,默认行为是生成内核转储;在Windows系统上,进程立即返回退出代码3 |
os.execl(path,arg0,arg1,…) | 该函数还有一系列功能历史的函数,比如os.execle(),os.execlp()等,这些函数都是适用参数列表arg0,arg1,…来执行path所代表的执行文件的 |
os.forkpty() | fork一个子进程 |
os.kill(pid,sig) | 将sig信号发送到gid对应的进程,用于结束该进程 |
os.kill(pgid,sig) | 将sig信号发送到pgid对应的进程组 |
os.popen(cmd,mode=‘r’,buffering=-1 | 用于向cmd命令打开读写管道(当mode=r时为只读,mode=rw时为读写,buffering缓冲参数与内置的open()函数有相同的含义。该函数返回的文件对象用于读写字符串,而不是字节。 |
os.spawnl(mode,path,…) | 此函数还有一系列功能类似的函数,比如os.spawnle(),os.spawnlp()等,这些函数都用于在新进程中执行新程序 |
os.startfile(path[,operation]) | 对指定文件适用该文件关联的工具执行operation对应的操作,如果不指定operation操作,则默认执行打开(open)操作。operation参数必须是有效的命令行操作项目,比如open(),edit(),print()等 |
os.system(command) | 运行操作系统上的指定命令 |
示例如下: |
import os
# 运行平台cmd命令
# **os.system('cmd')**
# 使用Excel打开g:\\abc.xls文件
os.startfile('g:\\abc.xls')
os.spawnl(os.P_NOWAIT,'E:\\Tools\\Notepad++.7.5.6.bin.x64\\notepad++.exe','')
# 使用python命令执行os_test.py程序
os.execl("D:\\Python\\Python36\\Python.exe","","os_test.py",'i')
如果直接运行上面的程序,可以看到程序运行后使用Excel打开了abc.xls文件,也打开了Notepad++工具,还使用python命令运行了os_test.py文件。但如果将程序中**包裹的代码启用,将看到程序运行后只启动了cmd命令,这是因为使用os.system()函数来运行程序,新程序所在的进程会替代原有进程。
在使用os.execl()函数运行新进程之后,也会取代原有的进程,因此上面程序将这行代码放在了最后。
21.1.3 random模块
random模块主要包含生成伪随机数的各种功能变量和函数,我们还是先来看一下它都包含哪些函数。
>>> import random
>>> random.__all__
['Random', 'SystemRandom', 'betavariate', 'choice', 'choices', 'expovariate',
'gammavariate', 'gauss', 'getrandbits', 'getstate', 'lognormvariate', 'normalvariate',
'paretovariate', 'randbytes', 'randint', 'random', 'randrange', 'sample', 'seed',
'setstate', 'shuffle', 'triangular', 'uniform', 'vonmisesvariate', 'weibullvariate']
>>>
方法 | 说明 |
random.seed(a=None,version=2) | 指定种子来初始化伪随机数生成器 |
random.randrange(start,stop[,step]) | 返回从start开始到stop结束,步长为step的随机数,其实就相当于choice(range(start,stop,step))的效果,只不过实际底层并不生成区间对象 |
random.randint(a,b) | 生成一个方位为a<=N<=b的随机数,其等同于randrange(a,b+1)的效果 |
random.choice(seq) | 从seq中随机抽取一个元素,如果seq为空,则引发IndexError异常 |
random.choices(seq,weights=None,*,cum_weights=None,k=1) | 从seq序列中抽取k个元素,还可通过weights指定各元素被抽取的权重(被抽取的可能性高低) |
random.shuffle(x[,random]) | 对x序列执行洗牌,随机排列操作 |
random.sample(population,k) | 从population序列中随机抽取k个独立元素 |
random.random() | 生成一个从0.0(包含)开始到1.0(不包含)之间的伪随机浮点数 |
random.uniform(a,b) | 生成一个范围为a<=N<=b的随机数 |
random.expovariate(lambd) | 生成一个呈指数分布的随机数,其中lambd参数(其实应该使lambda,只是lambda是关键字)为1除以期望平均值。如果lambd是正值,则返回的随机数从0至正无穷,为负值,返回从负无穷到0 |
21.1.4 time模块
time模块主要包含各种提供日期、时间功能的类和函数,该模块既提供了把日期、时间格式化为字符串的功能,也提供了从字符串恢复日期、时间的功能。
>>> import time
>>> [e for e in dir(time) if not e.startswith('_')]
['altzone', 'asctime', 'ctime', 'daylight', 'get_clock_info', 'gmtime', 'localtime', 'mktime', 'monotonic', 'monotonic_ns', 'perf_counter', 'perf_counter_ns', 'process_time', 'process_time_ns', 'sleep', 'strftime', 'strptime', 'struct_time', 'thread_time', 'thread_time_ns', 'time', 'time_ns', 'timezone', 'tzname']
>>>
在time模块内提供了一个time.struct_time类,该类代表一个时间对象,它主要包含9个属性,每个属性的信息如下:
字段名 | 字段含义 | 值 |
tm_year | 年 | 如2017、2018等 |
tm_mon | 月 | 如2,3等,范围1~12 |
tm_mday | 日 | 如2,3等,范围1~31 |
tm_hour | 时 | 如2,3等,范围1~23 |
tm_min | 分 | 如2,3等,范围0~59 |
tm_sec | 秒 | 如2,3等,范围0~59 |
tm_wday | 周 | 周一为0,范围0~6 |
tm_yday | 一年内的第几天 | 如65等,范围1~366 |
tm_isdst | 夏令时 | 0,1或-1 |
比如,Python可以用time.struct_time(tm_year=2022,tm_mon=7,tm_mday=8,tm_hour=14,tm_min=4,tm_sec=45,tm_wday=4,tm_yday=1,tm_isdst=0)很清晰地代表时间。 | ||
此外,Python还可以用一个包含9个元素的元组来代表时间,该元组的9个元素和struct_time对象中9个属性的含义是一一对应的,比如程序可以使用(2022,7,8,14,4,45,4,1,0)来代表时间。 | ||
在日期、时间模块内常用的功能函数如下: | ||
方法 | 说明 | |
– | – | |
time.asctime([t]) | 将时间元组或struct_time转换为时间字符串。如果不指定参数t,则默认转换当前时间 | |
time.ctime([secs]) | 将以秒数代表的时间转换为时间字符串,从1970年1月1日0点开始计算,由于时区问题,中国处于东八区,实际上从1970年1月1日8:00开始计算 | |
time.gmtime([secs]) | 将以秒数代表的时间转换为struct_time对象,如果不传入参数,则使用当前时间(格林尼治时间) | |
time.localtime([secs]) | 将以秒数代表的时间转换为代表当前时间的struct_time对象,如果不传入参数,则使用当前时间(本地时间,东八区) | |
time.mktime(t) | 他是localtime的反转函数,用于将struct_time对象或元组代表的时间转换为从1970.1.1日0点到现在的秒数 | |
time.perf_counter() | 返回性能计数器的值,单位秒 | |
time.process_time() | 返回当前进程使用CPU的时间,单位秒 | |
time.sleep(secs) | 暂停secs秒,什么都不干 | |
time.strftime(format[,t]) | 将时间元组或struct_time对象格式化为指定格式的时间字符串,如果不指定参数t,则默认转换当前时间 | |
time.strptime(string[,format]) | 将字符串格式的时间解析成struct_time对象 | |
time.time() | 返回从1970.1.1日0点到现在过来多少秒 | |
time.timezone | 返回本地时区的时间偏移,单位秒 | |
time.tzname | 返回本地时区的名字 | |
示例: |
>>> time.localtime()
time.struct_time(tm_year=2022, tm_mon=7, tm_mday=8, tm_hour=15, tm_min=7, tm_sec=44, tm_wday=4, tm_yday=189, tm_isdst=0)
>>> time.gmtime()
time.struct_time(tm_year=2022, tm_mon=7, tm_mday=8, tm_hour=7, tm_min=8, tm_sec=18, tm_wday=4, tm_yday=189, tm_isdst=0)
>>>
time.srftime()与time.strptime()涉及到编写格式模板,时间格式字符串支持的指令如下:
指令 | 含义 |
%a | 本地化的星期几的缩写名,比如Sun代表星期天 |
%A | 本地化星期几的完整名 |
%b | 本地化月份的缩写名,比如Jan代表表一月 |
% B | 本地化月份的完整名 |
% c | 本地化的日期和时间的表示形式 |
% d | 代表一个月中第几天的数值,范围:01-31 |
% H | 代表24小时制的小时,范围:00-23 |
% I | 代表12小时制的小时,范围:01-12 |
% j | 一年中第几天,范围:001-366 |
% m | 代表月份的数值,范围:01-12 |
%M | 代表分钟的数值,范围:00-59 |
% p | 上午或下午的本地化方式,当使用strptime()函数并使用%I指令解析小时时,%p只影响小时字段 |
%S | 代表分钟的数值,范围:00-61,60在表示闰秒的时间戳时有效,61则是由于一些历史原因造成的 |
%U | 代表一年中的第几周,以星期天为每周第一天,范围:00-53,在这种方式下,一年中第一个星期天被认为处于第一周,当使用strptime()函数解析时间字符串时,只有何时指定了星期几和年份该指令才生效 |
%w | 代表星期几的数值,范围:0-6,其中0代表周日 |
% W | 代表一年中第几周,以星期一为每周的第一天,范围:00-53,在这种方式下,一年中第一个星期一被任务处于第一周,当使用strotime()函数解析时间字符串时,只有同时指定了星期几和年份,该指令才生效 |
%x | 本地化的提起表示形式 |
% X | 本地化时间表示形式 |
% y | 年份的缩写,范围:00-99.比如2018简写成18 |
%Y | 年份的完整形式 |
% z | 显示时区偏移 |
% Z | 时区名 |
% % | 代表% |
21.1.5 itertools模块(函数相关)
在itertools模块中,主要包含了一些生成迭代器的函数,
>>> import itertools
>>> [e for e in dir(itertools) if not e.startswith('_')]
['accumulate', 'chain', 'combinations', 'combinations_with_replacement', 'compress',
'count', 'cycle', 'dropwhile', 'filterfalse', 'groupby', 'islice', 'permutations',
'product', 'repeat', 'starmap', 'takewhile', 'tee', 'zip_longest']
>>>
- 生成无限迭代器
- count(start,[step]):生成start开始,步进为step(默认1)的迭代器,
- cycle§:生成序列p无限循环的迭代器,
- repeat(elem[,n]):生成n个元素elem重复的迭代器,不指定n,则生成无限循环。
- 其他常用迭代器函数
- accumulate(p[,func]):生成按照func函数计算序列p内元素形成的迭代器,如果不指定func,默认生成序列p元素累加迭代器,p0,p0+p1,p0+p1+p2,…
- chain(p,q,…):将多个序列元素”链“在一起,形成新的迭代器
- compress(data,selectors):根据selectors序列的值对data序列的元素进行过滤,如果selectors[0]的值为真,保留data[0],否则删除,以此类推。
- dropwhile(pred,seq):使用pred函数对seq序列进行过滤,保留从第一个计算为False的元素seq[i]开始至结束的元素。
- takewhile(pred,seq):与上一函数相反,去掉从第一个计算结果为False的seq[i]至结束的元素
- filterfalse(pred,seq):保留序列seq中,使用pred计算结果为True的值
- islice(seq,[start,]stop[,step]):类似于序列的切片slice()函数,返回seq[start:stop:step]的结果
- starmap(func,seq):使用func()对seq的元素进行计算,返回计算结果的迭代器,支持序列解包,即seq中多个元素给func传递参数,输出结果。所以变换后的序列长度未必等于len(seq)
- zip_longers(p,q,…)将p,q等序列中的元素按索引合并成元组,这些元组将作为新学列的元素。
- 生成排列组合的工具函数
- product(p,q,…[repeat=1]):用学了p,q中的元素进行排列组合,相当于使用嵌套循环组合。
- permutations(p,[,r]):从序列p中取出r个元素组成全排列,将排列得到的元组作为新迭代器的元素
- combinations(p,r):从序列p中取出r个元素组成全组合,元素不允许重复,将组合得到的元组作为新迭代器的元素
- conbinations_with_replacement(p,r):从序列p中取出r个元素组成全组合,元素允许重复,将组合得到的元组作为新迭代器的元素。
示例:
import itertools as it
#product 使用两个序列进行排列组合
for e in it.product('AB','CD'):
print(''.join(e),end=',') # AC, AD, BC, BD,
#product 使用一个序列,重复两次进行排列组合
for e in it.product('AB',repeat=2):
print(''.join(e),end=',') # AA, AB, BA, BB,
>>> [e for e in it.permutations('ABCD',2)]
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'A'), ('B', 'C'), ('B', 'D'), ('C', 'A'), ('C', 'B'), ('C', 'D'), ('D', 'A'), ('D', 'B'), ('D', 'C')]
>>> [e for e in it.combinations('ABCD',2)]
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
>>> [e for e in it.combinations_with_replacement('ABCD',2)]
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'B'), ('B', 'C'), ('B', 'D'), ('C', 'C'), ('C', 'D'), ('D', 'D')]
>>>
21.1.6 functools模块
functools模块中主要包含了一些函数装饰器和便捷的功能函数。
>>> import functools
>>> [e for e in dir(functools) if not e.startswith('_')]
['GenericAlias', 'RLock', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES', 'cache',
'cached_property', 'cmp_to_key', 'get_cache_token', 'lru_cache', 'namedtuple', 'partial',
'partialmethod', 'recursive_repr', 'reduce', 'singledispatch', 'singledispatchmethod',
'total_ordering', 'update_wrapper', 'wraps']
>>>
- functools.lru_cache(maxsize=128,type=False): 该函数装饰器使用LRU(最近最少使用)缓存算法来缓存相对耗时的函数结果,避免传入相同的参数重复计算。同时,缓存并不会无限增长,不用的缓存会被释放。其中,maxsize参数用于设置缓存只占用的最大字节数。typed参数用于设置将不同类型的缓存结果分开存放
- functools.cmp_to_key(func):将func转换为关键字函数
- @functools.total_ordering:这个类装饰器(作用类似于函数装饰器,只是它用于装饰类)用于为类自动生成比较方法。通常来说,开发者只要提供–lt–()-、–le–()-、–gt–()-、–ge–()其中之一(最好能提供–eq–()方法),@functools.total_ordering装饰器就会为该类生成剩下的比较好的方法。
- functools.partial(func,*args,**keywords):该函数用于为func函数的部分参数指定参数值,从而得到一个转换后的函数,程序以后调用转换后的函数时,就可以少传入哪些已指定值的参数。
- functools.partialmethod(func,*args,**keywords):该函数与上一函数含义完全相同,只不过该函数用于为类中的方法设置参数
- functools.reduce(function,iterable[,initialzer]):将初始值(默认为0,可由initialzer参数指定)、迭代器的当前元素传入function函数,将计算出来的函数结果作为下一次计算的初始值、迭代器的下一元素再次调用function函数,以此类推,直到迭代器的最后一个元素。
- @functools.singledispatch:该函数装饰器用于实现函数对多个类型进行重载。比如同样的函数名称,为不同的参数类型提供不同的功能实现,该函数的本质就是根据参数类型的变换,将函数转向调用不同的函数。
- functools.update_wrapper(wrapper,wrapped,assigned=WRAPPER_ASSIGNMENTS,updated=WRAPPER_UPDATES):对wrapper函数进行包装,使之看上去就像wrapper(被包装)函数。
- functools.wraps(wrapped,assigned=WRAPPER_ASSIGNMETS,updated=WRAPPER_UPDATES):该函数装饰器用于修饰包装函数,使包装函数看上去就像wrapper函数。
from functools import *
#设初始值(默认为0)为x,当序列元素为y,将x+y作为下一次初始值
print(reduce(lambda x,y:x+y,range(5))) #10
print(reduce(lambda x,y:x+y,range(6))) #15
#设初始值为10
print(reduce(lambda x,y:x+y,range(6),10)) +25
class User:
def __init__(self,name)
self.name = name
def __repr__(self)
return 'User[name]=%s'% self,name
#定义一个老式的大小比较函数,User的那么越长,该User越大
def old_cmp(u1,u2)
return len(u1.name)-len(u2.name)
my_data = [User('kotlin'),User('Swift'),User('Go'),User('Java')]
# 对my_data排序,需要将关键字函数(调用cmp_to_key将old_cmp转换为关键字函数)
my_data.sort(key=cmp_to_key(old_cmp))
Print (my_data)
@lru_cache(maxsize=32)
def factorial(n):
print(’计算 %d 的阶乘',%n)
if n==1:
return 1
else:
return n*factorial(n-1)
#只有这行会计算,然后会缓存5、4、3、2、1的阶乘
print(factorial(5))
print(factorial(3))
print(factorial(5))
#内置函数int函数默认将十进制的字符串转换为整数
print(int('1234')
# 为int函数的base参数指定参数值
basetwo = partial(int,base =2 )
basetwo.__doc__ = '将二进制形式的字符串转换为整数'
#相当于执行base=2的int函数(将二进制的字符串转为十进制)
print(basetwo('10010')) #18
print(int('10010',2)) #18
partialmethod()与partial()函数的作用基本相似,只是用于类方法部分参数值绑定。
from functools import *
class Cell:
def __init__(self):
self.alive = False
# @property装饰器指定该方法可使用属性语句访问
@property
def alive(self):
return self._alive
def set_state(self,state):
self.alive = bool(state)
#指定set_alive()方法,就是将set_state()方法的state参数指定为Ture
set_alive = partialmethod(set_state,Ture)
#指定set_dead()方法,就是将set_state()方法的state参数指定为False
set_dead = partialmethod(set_state,False)
c = Cell()
print(c.alive) # False
#相当于调用c.set_state(Ture)
c.set_alive()
print(c.alive) # Ture
#相当于调用c.set_state(False)
c.set_alive()
print(c.alive) # False
下面示范@total_ording类装饰器的作用。
from functools import *
@total_ordering
class User:
def __init__(self,name):
self.name = name
def __repr__(self):
return 'User|name=%s'% self.name
#根据是否有name属性决定是否可比较
def _is_valid_operand(self,other):
#内置函数hasattr()判断other对象中是否有name属性
rentrn hasattr(other,"name")
def __eq__(self,other):
if not self._is_valid_operaned(other)
return NotImplemented
#根据name判断是否相等(都转换成小写比较,或略大小写)
return self.name.lower() == other.lastname.lower()
def __lt__(self,other):
if not self._is_valid_operaned(other)
return NotImplemented
#根据name判断是否小于(都转换成小写比较,或略大小写)
return self.name.lower() < other.lastname.lower()
#打印被装饰之后的User类中的__gt__方法
print(User.__gt__) #自动生成了大于的比较
@singledispatch函数装饰器的作用使根据函数参数类型,实现调用不同的函数。
from functools import *
@singledispatch
def test(are,verbose):
if verbose:
print('默认参数为:',end = "")
print(arg)
#限制test函数的第一个参数为int类型的函数版本,register()方法是使用@singledispatch修饰后,自动添加的方法,用于为指定类型注册被转向调用的函数。
@test.register(int)
def (argu,verbose):
if verbose:
print('整型参数为:',end = "")
print(argu)
test('Python',True) #默认参数为:Python
test(20,True) #整型参数为:20
21.1.7 JSON及json模块
JSON是一种轻量级、跨平台、跨语言的数据交换格式,JSON格式被广泛应用于各种语言的数据交换中,Python也提供了对JSON的支持。
21.1.7.1 JSON基础知识
JSON全称是JavaScript Object Notation,即JavaScript对象符号。
JSON主要有两种数据结构:
- 由key-value对组成的数据结构,在Python中对应dict(字典)结构。
- 有序集合,在Python中对应列表。
JavaScrip1.2开始创建对象的方法如下:
使用JSON语法创建对象:
object =
{
porpertyName1:porpertyValue1,
porpertyName2:porpertyValue2,
...
porpertyNamen:porpertyValuen
}
以上示例是使用JSON语法创建的是JavaScript对象,属性值可以是函数、数组,甚至是另一个JSON对象。
使用JSON语法创建数组:
var a = ['value1','value2',...,valuen];
JSON数据结构与Python结构转换关系如下表:
JSON类型 | Python类型 |
对象(object) | 字典(dict) |
数组(array) | 列表(list) |
字符串(string) | 字符串(str) |
整数(number(int)) | 整数(int) |
实数(number(real)) | 浮点数(float) |
ture | Ture |
false | False |
null | None |
鉴于JSON语法简单易用,而且作为数据传输载体时,数据传输量更小,因此在夸平台的数据交换中,往往采用JSON作为数据交换的格式。 | |
Python使用json模块将数据转换为JSON格式,然后在进行传输,跨语言处理操作等,最后在恢复成Python使用的数据结构进行处理。下面我们介绍Python的json模块。 |
21.1.7.2 Python的json模块
>>> import json
>>> json.__all__
['dump', 'dumps', 'load', 'loads', 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder']
>>>
json模块中使用的函数主要有4个,功能如上图所示。
- json.dump(obj,fp,*,skipkeys=False,ensure_ascii=Ture,check_circular=Ture,allow_nan=Ture,cls=None,indent=None,separator=None,default=None,sort_keys=False,**kw):将obj对象转换成JSON字符串并输出到fp流中,fp是一个支持write()方法的类文件对象。
- json.dumps(obj,*,skipkeys=False,ensure_ascii=Ture,check_circular=Ture,allow_nan=Ture,cls=None,indent=None,separator=None,default=None,sort_keys=False,**kw):将obj对象转换为JSON字符串,并返回该字符串。
- json.load(fp,*,cls=None,object_hook=None,pares_float=None,pares_int=None,parse_constant=None,object_pairs_hook=None,**kw): 从fp流读取JSON字符串,将其恢复成Python对象,其中,fp是一个支持write()方法的类文件对象。
- json.loads(s,*,encoding=None,cls=None,object_hook=None,pares_float=None,pares_int=None,parse_constant=None,object_pairs_hook=None,**kw): 将JSON字符串s恢复成Python对象。
编码示例:
import json
# 将Python对象(元组会被当成数组)转换为JSON字符串
s = json.dumps(['python',{'favorite':('C','C++','Java',25)}])
print(s) #['python',{'favorite':['C','C++','Java',25]}]
# 字典对象转换为JSON对象
s2 = json.dumps({'c':0,'b':0,'a':0},sort_keys=Ture)
print(s2) #{'a':0,'b':0,'c':0}
#将列表转换为JSON字符串,并指定分隔符
s3 = json.dumps([1,2,3,{'x':4,'y':5}],separators=('&'))
#此时会报错,因为我们缺少了一个指定的分隔符,指定分隔符要指定两个,一个用于元素分割,一个用于字典定义分割。
s4 = json.dumps([1,2,3,{'x':4,'y':5}],separators=('&','$'))
print(s4) # [1&2&3&{"x"$4&"y"$5}]
# 指定indent为4,意味着转换的JSON字符串有缩进
s5 = json.dumps({'Python':5,'C':7},sort_keys=True,indent=4)
print(s5)
#
{
"C": 7,
"Python": 5
}
s5 = json.dumps({'Python':5,'C':7},sort_keys=True,indent=10)
print(s5)
#
{
"C": 7,
"Python": 5
}
#打开一个文件,如果没有则新建一个
f = open('a.json','w')
#使用dump()函数将转换得到的JSON字符串输出到文件中
json.dump(['C','Python],f)
dumps()与dump()的功能,所支持选项基本相同,只是dumps()直接返回JSON字符串,dump()将转换的字符串输出到文件
解码示例:
#直接解码的方式基本与编码相同,不在举例
#解码可以自定义解码函数,以便于完成Python特殊类型(如复数、矩阵)的转换
#定义一个自定义转换函数
def as_comlpex(dct)
if '__complex__'in dct:
return complex(dct['real'],dct['imag'])
return dct
# 使用自定义的恢复函数
#自定义的恢复函数将real数据转换为复数的实部,将imag转换为虚部
result = json.loads({'__complex__':Ture,'real':1,'imag':2},object_hook=as_complex)
print (result) #(1+2j)
f=open('a.json')
result2 = json.load(f)
print(result2) #['C','Python]
Python支持的数据类型要比JSON丰富的多,比如复数、矩阵等,如果直接使用dumps()或dump()函数进行转换,程序肯定会出问题。此时就需要开发者对JSONEncoder类进行扩展。
例如:
import json
#定义JSONEncoder的子类
class ComplexEncoder(json.JSONEncoder):
def default(self,obj):
#如果需转换的对象是复数,程序负责处理
if isinstance(obj,complex):
return {"__complex__":'Ture','real':obj.real,'imag':obj.imag}
#对于其他类型,直接使用JSONEncoder处理
return json.JSONEncoder.default(self,obj)
#使用dumps()或dump()函数中通过cls属性指定自定义子类处理
s1 = json.dumps(2+1j,cls=ComplexEncoder)
print(s) # '{"__complex__":'ture','real':2.0,'imag':1.0}'
直接使用JSONEncoder的自定义子类的encode()方法转换
s2 = ComplexEncoder().encode(2+1j)
print(s2) # '{"__complex__":'ture','real':2.0,'imag':1.0}'