python可能需要借助于其他库更便捷的完成任务,同时一个源文件中不可能编写整个程序的源代码,这些都需要使用模块化的方式来组织项目的源代码
包括
python标准库中的模块
用户自定义的实现特定功能的以.py为后缀名的文件
导入语法
import 模块名1 [as 别名1],模块名2 [as 别名2],... from 模块名 import 成员1 [as 别名1],成员2 [as 别名2],... 其中 第一种格式导入整个模块,使用成员时必须添加模块名或模块别名前缀 第二种格式导入模块里的某些成员,直接使用成员,无须任何前缀 [as 别名1]可以选择是否将模块设置别名
示例
import sys,os print(sys.argv[0]) print(os.sep) import sys as s,os as o print(s.argv[0]) print(o.sep) from sys import argv from os import sep print(argv[0]) print(sep) from sys import argv as ar from os import sep as se print(ar[0]) print(se)
linux设置环境变量查找python自定义模块
vi /etc/profile export PYTHONPATH=$PYTHPATH:/app/scripts
source /etc/profile 其中 /app/scripts为自定义模块存放路径
自定义模块的编写
/app/scripts/__Sub.py自定义模块程序清单
class Father(object): def __init__(self, name): self.name = name print(‘父类__init__方法‘) def getName(self): print(‘父类getName方法‘) return ‘Father name: ‘+self.name class Son(Father): #重写父类的__init__方法,父类中的__init__方法会被覆盖 def __init__(self,name): super().__init__(name)print(‘子类__init__方法‘) #重写父类中的getName方法,父类的getName方法被覆盖 def getName(self): print(‘子类getName方法‘) print(Father.getName(self)) return ‘Son name: ‘+self.name
导入自定义模块
import __Sub #调用模块中的Son类 son = __Sub.Son(‘test_class‘) #调用模块中Son类的getName方法 print(son.getName())
该模块提供了一些与Python解释器相关的功能
sys.argv 传递给Python脚本的命令行参数列表,argv[0]代表脚本名,argv[n]代表传入脚本的第n个参数,n>0且为整数 sys.byteorder 本地字节序的指示符,若是大端模式,该值为big,若是小端模式,为little sys.exit([arg]) 引发 SystemExit 异常退出当前程序 arg: 可选参数,表示退出状态的整数(默认0表示程序运行成功终止),也可以是其他类型的对象 sys.getfilesystemencoding() 返回当前系统保存文件所用的字符集 sys.maxsize 返回python整数支持的最大值,32位平台为2**31-1,64为平台为2**63-1 sys.modules 返回模块名和载入模块对应关系的字典 sys.path 返回python查找模块路径的列表 sys.platform 返回平台标识符 sys.stdin 返回标准输入流 sys.stout 返回标准输出流 sys.stderr 返回标准错误流 sys.version 返回python解释器的版本号
该模块提供了一些与程序运行所在操作系统的相关信息
os.environ 返回当前系统所有环境变量组成的map对象 os.fspath(dir) 返回dir的文件系统表示 传入str或bytes类型,则返回的值不变,传入其他类型,引发 TypeError 异常 os.getenv(key, default=None) 返回指定环境变量 key 的值,否则返回 default, key ,default 和返回值均为 str 字符串类型 os.getegid() 返回当前进程的有效组ID,仅对unix系统有效 os.geteuid() 返回当前进程的有效用户标识,仅对unix系统有效 os.getgid() 返回当前进程的真实组ID,仅对unix系统有效 os.getgrouplist(user, group) 返回user所属的组ID的列表。如果group不在列表中,则将其包括在内,仅对unix系统有效 os.getgroups() 返回与当前进程关联的补充组ID的列表 os.getlogin() 返回通过控制终端进程进行登录的用户名 os.getpgid(pid) 返回进程ID为pid的进程的进程组ID,仅对unix系统有效 os.getpgrp() 返回当前进程组的ID,仅对unix系统有效 os.getpid() 返回当前进程ID os.getppid() 返回父进程ID 当父进程已经结束,在Unix中返回的ID是初始进程(1)中的一个 os.getresgid() 返回一个元组(rgid, egid, sgid),表示当前进程的真实,有效和已保存的组ID,仅对unix系统有效 os.getresuid() 返回一个元组(ruid, euid, suid),表示当前进程的真实,有效和已保存的用户ID,仅对unix系统有效 os.getuid() 返回当前进程的真实用户ID,仅对unix系统有效 os.putenv(key, value) 将名为 key 的环境变量值设置为 value os.setegid(egid) 设置当前进程的有效组ID,仅对unix系统有效 os.seteuid(euid) 设置当前进程的有效用户ID,仅对unix系统有效 os.setgid(gid) 设置当前进程的组ID,仅对unix系统有效 os.setgroups(groups) 将与当前进程关联的补充组ID列表设置为 groups,仅对unix系统有效 groups必须是一个序列,每个元素必须是标识一个组的整数 此操作通常仅对超级用户可用 os.setregid(rgid, egid) 设置当前进程的真实组ID和有效组ID,仅对unix系统有效 os.setresgid(rgid, egid, sgid) 设置当前进程的真实,有效和已保存的组ID,仅对unix系统有效 os.setresuid(ruid, euid, suid) 设置当前进程的真实,有效和已保存的用户ID,仅对unix系统有效 os.setreuid(ruid, euid) 设置当前进程的真实,有效的用户ID,仅对unix系统有效 os.umask(mask) 设置掩码,并返回上一个掩码 os.uname() 返回标识当前操作系统的信息,拥有以下五个属性: sysname: 操作系统名称 nodename: 计算机名称 release: 操作系统版本 version: 操作系统版本 machine: 硬件标识符 os.unsetenv(key) 删除环境变量key
os.execl(path, arg0, arg1, ...)
执行一个新程序,以替换当前进程,没有返回值
os.fork()
分叉子进程,在父级中返回子级和子级的进程ID,发生错误引发 OSError 异常
os.forkpty()
使用新的伪终端作为子进程的控制终端,返回一对 (pid, fd)
os.kill(pid, sig)
将信号 sig 发送至进程 pid
os.killpg(pgid, sig)
将信号sig发送到进程组pgid,仅对unix系统有效
os.system(command)
在子 shell 中执行command(字符串)
os.times()
返回当前的全局处理时间,拥有以下五个属性:
user: 用户时间
system: 系统时间
children_user: 所有子进程的用户时间
children_system: 所有子进程的系统时间
elapsed: 从过去的固定点过去的实时时间
os.wait()
等待子进程完成,并返回一个包含其pid和退出状态指示的元组
os.close(fd) 关闭文件描述符fd os.open(path, flags, mode=0o777, *, dir_fd=None) 打开文件 os.openpty() 打开一个新的伪终端 os.pipe() 创建一个管道,返回一对分别可用于读取和写入的文件描述符 os.read(fd, n) 从文件描述符fd读取最多n个字节并返回 os.write(fd, str) 将str中的字节串写入文件描述符fd中
os.chdir(path) 指定当前工作目录为path,仅对unix系统有效 os.chmod(path, mode, *, dir_fd=None, follow_symlinks=True) 修改path的权限 os.chown(path, uid, gid, *, dir_fd=None, follow_symlinks=True) 修改path的所属于用户和所属组,仅对unix系统有效 os.chroot(path) 将当前进程的根目录更改为path,仅对unix系统有效 os.getcwd() 返回包含当前工作目录路径的字符串 os.getcwdb() 返回一个代表当前工作目录的字节串 os.link(src, dst, *, src_dir_fd=None, dst_dir_fd=None, follow_symlinks=True) 创建一个名称为dst指向src的硬链接 os.listdir(path) 返回path下所有的目录和文件 os.mkdir(path, mode=0o777, *, dir_fd=None) 创建path目录,权限为mode,目录已经存在,引发 FileExistsError 异常 os.makedirs(name, mode=0o777, exist_ok=False) 递归创建目录,权限为mode exist_ok为默认False时,目录存在引发 FileExistsError 异常 os.remove(path, *, dir_fd=None) 删除path,如果path是目录,引发 IsADirectoryError 异常 os.removedirs(path) 递归删除目录 os.rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None) 将文件或目录src重命名为dst,如果存在dst,引发 OSError 异常 os.rename(src, dst) 递归目录或文件重命名功能 os.rmdir(path, *, dir_fd=None) 删除目录,如果目录不存在或不为空,则分别引发 FileNotFoundError 或 OSError 异常 os.stat(path, *, dir_fd=None, follow_symlinks=True) 获取文件或文件描述符的状态 os.symlink(src, dst, target_is_directory=False, *, dir_fd=None) 创建一个指向src的符号链接(软链接),名为dst
os.cpu_count() 返回系统中的CPU数量 os.linesep 返回当前系统的换行符,linux为”\n”,windows为”\r\n” os.name 返回当前操作系统名称 os.pathsep 返回当前系统多条路径之间的分隔符,linux为”:”,windows为”;” os.sep 返回当前系统的路径分隔符,linux为‘/‘,windows为‘\\‘
该模块主要包含生成伪随机数的功能
random.seed(num-None, version=2)
指定种子来初始化随机数生成器,没有返回值,num为不同值时,生成的随机数不同
random.randrange(stop)
random.randrange(start, stop[, step])
只有stop时返回一个 [0,stop) 的随机整数
返回一个范围是 [start,stop),步长为 step 的随机整数
random.randint(a, b)
返回一个 range(a,b+1) 之间的一个随机整数
random.choice(seq) 从序列 seq 返回一个随机元素,如果 seq 为空,则引发 IndexError 异常 random.choices(seq, weigths=None, *, cum_weights=None, k=1) 从序列 seq 中抽取 k 个元素,weigths表示抽取的概率 random.shuffle(x, random) 将序列 x 洗净重新排列 random.sample(seq, k) 从序列 seq 中抽取 k 个元素
random.random() 返回一个 [0.0, 1.0) 范围内的随机浮点数 random.uniform(a, b) 返回一个 [a,b] 范围内的随机浮点数
该模块包含了各种时间访问和转换相关的功能
epoch(纪元) 时间开始的点,即从那天开始计时,取决于平台:Unix的epoch是1970年1月1日00:00:00(UTC)
UTC 协调世界时。世界标准时间(以前称为格林威治标准时间,或GMT)
DST 夏令时。表示为了节约能源,人为规定时间
time.struct_time类 代表一个包含时间对象的元组,元组内容为:(年,月,日,时,分,秒,周,一年内的第几天,夏令时) time.asctime(t) 把struct_time或元组转换为时间字符串 如果t=None或未提供,使用 localtime() 所返回的当前时间 time.ctime(secs) 将自 epoch 开始的秒数转换为时间字符串 如果 secs=None或未提供,则使用 time() 返回的当前时间 time.gmtime(secs) 将自 epoch 开始的秒数转换为 UTC 的 struct_time 如果 secs=None或未提供,则使用 time() 返回的当前时间 time.localtime(secs) 将自 epoch 开始的秒数转换为当地时间的 struct_time 如果 secs=None或未提供,则使用 time() 返回的当前时间 time.mktime(t) localtime() 的反函数,用于将 struct_time 或元组表示的时间转化为从 epoch 到现在过了多少秒 time.sleep(secs) 暂停secs秒 time.strftime(format, t) 将时间struct_time或时间元组格式化为指定格式format的时间字符串 如果t未指定,则使用time()所返回的时间 time.strptime(string, format) 将字符串格式的时间转化为struct_time time.time() 返回从 epoch 开始到现在的秒数,返回类型为浮点数 time.timezone 返回本地时区与UTC的偏移量,单位秒 time.tzname 返回一个元组,元组内容: (本地非DST时区的名称,本地DST时区)
%a 本地化的星期几的缩写名称 %A 本地化的星期几的完整名称 %b 本地化的月缩写名称 %B 本地化的月完整名称 %c 本地化的适当日期和时间表示 %d 一个月中的第几天, 范围 [01,31] %H 24小时制的小时,范围 [00,24] %I 12小时制的小时,范围 [01,12] %j 一年中的第几天,范围 [001,366] %m 月份,范围 [01,12] %M 分钟,范围 [00,59] %p 本地化的 AM 或 PM %S 秒,范围 [00,61] %U 一年中的第几周,范围 [00,53],以星期日为每周的第一天,在第一个星期日之前的新年中的所有日子都被认为是在第0周 %w 星期几,范围 [0(星期日),6] %W 一年中的第几周,范围 [00,53],以星期一为每周的第一天,在第一个星期一之前的新年中的所有日子被认为是在第0周 %x 本地化的适当日期表示 %X 本地化的适当时间表示 %y 年份缩写,范围 [00,99] %Y 完整的年份 %z 时区偏移以格式 +HHMM 或 -HHMM 形式的 UTC/GMT 的正或负时差指示,其中H表示十进制小时数字,M表示小数分钟数字 [-23:59, +23:59] %Z 时区名称(如果不存在时区,则不包含字符) %% 字面的 ‘%‘ 字符
该模块提供了正则表达式匹配相关功能
. 通配符,匹配除了换行的任意字符 如果指定了DOTALL旗标,匹配包括换行符在内的任何字符 ^ 匹配字符串的开头 MUTILINE模式下,还匹配每个换行符之后的字符串 $ 匹配字符串尾或者换行符的前一个字符 MULTILINE模式下,还匹配换行符的前面 * 前面的RE重复0到任意次,等价于 {0,} + 前面的RE重复1到任意次,等价于 {1,} ? 前面的RE重复0到1次,等价于 {0,1} {m} 前面的RE重复 m 次 {m,n} 前面的RE重复 m 到 n 次匹配,在 m 和 n 之间取尽量多 省略m表示无限匹配,省略n表示可以重复0次 {m,n}? 前面的RE重复 m 到 n 次匹配,只匹配尽量少的字符次数 转义符 [...] 匹配 [...] 中的任意一个字符 如 [pyt] 匹配 ‘p‘ 或 ‘y‘ 或 ‘t‘ [^...] 匹配不在 [^...] 中的字符,如 [^abc] 匹配除了 ‘a‘ , ‘b‘ 和 ‘c‘ 之外的 | 匹配其中任何一项 如 ’A’|’B’ 匹配A或者B (...) 匹配 (...) 以及指定一个子组,可以通过 \1,\2,... 依次捕获引用 如 r‘(e|r|q)A*(T|Z)\1[F|G]{0,5}\2‘ 其中 (e|r|q) 表示子组1,可以匹配‘e‘ 或 ‘r‘ 或 ‘q‘,\1 必须和 (e|r|q) 的匹配相同 (T|Z) 表示子组2,可以匹配 ‘T‘ 或 ‘Z‘,\2 必须也和 (T|Z) 的匹配相同 (?:...) 匹配 (...) 以及指定一个子组,但是子组不可捕获 非捕获组,即该子组匹配的字符串无法捕获 上面的例子中 \1 和 \2 不能使用 (?P<name>…) 匹配 (...) 并且为子组命名为 name ,name必须唯一 可以通过 (?P=name) 捕获引用,也可以通过 \1,\2,... 依次捕获引用 (?P=name) 引用一个名为 name 的子组 (?#...) 注释组,?#后面的内容是注释,不影响正则结果 (?=…) 匹配后面带有 (...) 的字符串,但是 (...) 不作为匹配 如 re.search(r‘.*docs\.(?=python)‘, r‘https://docs.python.org/release/3.8.4/library/re.html‘) 匹配到 ‘https://docs.‘ 子串 (?!…) 匹配后面不带有 (...) 的字符串,但是 (...) 不作为匹配 如 re.search(r‘(https).*docs\.(?!PYTHON)‘, r‘https://docs.python.org/release/3.8.4/library/re.html‘) 匹配到 ‘https://docs.‘ 子串 (?<=…) 匹配前面带有 (...) 的字符串,但是 (...) 不作为匹配 如 re.search(r‘(?<=https://)docs\.‘, r‘https://docs.python.org/release/3.8.4/library/re.html‘) 匹配到 ‘docs.‘ 子串 (?<!…) 匹配前面不带有 (...) 的字符串,但是 (...) 不作为匹配 如 re.search(r‘(?<!http://)docs\.‘, r‘https://docs.python.org/release/3.8.4/library/re.html‘) 匹配到 ‘docs.‘ 子串 \A 只匹配字符串开头 \b 匹配单词的边界,即开始或结尾,单词被定义为 Unidcode 的字母,数字或下横线字符 如 re.search(r‘\bver‘, r‘verb‘) 可以匹配到开头的 ‘ver‘,但 re.search(r‘\bver‘, r‘never‘) 不能匹配 如 re.search(r‘er\b‘, r‘never‘) 可以匹配到结尾的 ‘er‘,但 re.search(r‘er\b‘, r‘verb‘) 不能匹配 \B 匹配非单词边界 如 re.search(r‘er\B‘, r‘verb‘) 可以匹配到 ‘er‘, 但 re.search(r‘er\B‘, r‘never‘) 不能匹配 \d 匹配任意数字,等价于 [0-9] \D 匹配任意非数字,等价于 [^0-9] \s 匹配任意空白字符,包括空白格,制表符,回车符,换页符,换行符,等价于 [\t\n\r\f\v] \S 匹配任意非空白字符,等价于 [^\t\n\r\f\v] \w 匹配所有单词字符,包括0-9的数字,26个英文字母和下划线,等价于 [a-zA-Z0-9] \W 匹配非单词字符,等价于 [^a-zA-Z0-9] \Z 只匹配字符串的结尾,如果是存在换行,只匹配到换行前的结束字符串
match对象的布尔值始终是True,但是可以使用 if 判断是否有匹配到
如:
if re.serach(pattern, string):
do_something
match对象常用方法、属性
match.expand(template) 返回通过对模板字符串template进行反斜杠替换而获得的字符串,类似于 re.sub() 方法 match.group(group1, ...) 返回匹配项的一个子组字符串或多个子组组成的元组 不提供group时返回整个匹配项 如: m = re.match(r‘(\w+)( \w+).*‘, r‘python is very easy!‘) m.group() #返回匹配到的所有项 ‘python is very easy!‘ m.group(1) #返回子组1匹配到的项 ‘python‘ m.group(1, 2) #返回子组1,子组2匹配到的项组成的元组 (‘python‘, ‘ is‘) match.groups(default=None) 返回一个包含匹配项所有子组的元组 m.groups() #返回所有子组匹配到的项组成的元组 (‘python‘, ‘ is‘) match.start(group) match.end(group) 返回组匹配的子字符串的开始和结束的索引 不提供group时表示整个匹配的子字符串 m.start(1) #返回子组1匹配到的项开始的索引 m.start(2) #返回子组2匹配到的项开始的索引 m.end(1) #返回子组1匹配到的项结束的索引 m.end() #整个匹配的子字符串结束的索引 match.span(group) 返回组匹配的子字符串的开始和结束的索引组成的元组 不提供group时表示整个匹配的子字符串开始和结束的索引组成的元组
re.A = re.ASCII 控制\w, \W, \b, \B, \d, \D, \s和\S 只匹配 ASCII 字符,而不匹配所有的 Unicode 字符 re.DEBUG 显示已编译的正则表达式的Debug信息,没有行内标旗标 re.I = re.IGNORECASE 不区分大小写匹配 如 re.match(r‘python‘, r‘PYTHON is very easy!‘, re.I) 匹配到 ‘PYTHON‘ re.L = re.LOCALE 根据当前环境设置不区分大小写匹配 re.M = re.MULTILINE 多行模式 re.S = re.DOTAL 使 ‘.‘ 匹配包括换行符在内的所有字符 re.X = re.VERBOSE 允许注释分行
re.compile(pattern, flags=0) 将正则表达式编译为一个正则表达式对象(正则对象),常用于单个程序中多次使用相同的正则表达式 flags: 标志位,用于控制正则表达式的匹配方式:是否区分大小写,多行匹配等等 如 prog = re.compile(pattern) result = prog.match(string) 等价于 result = re.match(pattern, string) re.match(pattern, string, flags=0) 从 string 开始位置匹配 pattern,匹配到则返回match对象,否则返回 None 如 re.match(r‘PYTHON‘, r‘PYTHON is very easy!‘) re.search(pattern, string, flags=0) 扫描整个 string,返回第一个与 pattern 匹配的match对象,否则返回 None re.findall(pattern, string, flags=0) 扫描整个 string,返回所有与 pattern 匹配的子串组成的列表,若 pattern 中含有捕获组时会优先返回捕获组结果组成的列表 如 re.findall(r‘^[a-z0-9]+@[a-z0-9-]+(.[a-z]{2,5}){1,2}$‘, r‘123456@qq.com‘) 返回捕获组 (.[a-z]{2,5} 结果组成的列表: [‘.com‘] 如 re.findall(r‘^[a-z0-9]+@[a-z0-9-]+(?:.[a-z]{2,5}){1,2}$‘, r‘123456@qq.com‘) 返回 [‘123456@qq.com‘] 列表 re.finditer(pattern, string, flags=0) 扫描整个 string ,返回所有与 pattern 匹配的子串match对象组成的迭代器 re.fullmatch(pattern, string, flags=0) string 与 pattern 完全匹配返回match对象,,否则返回 None re.purge() 清除正则表达式缓存 re.split(pattern, string, maxsplit=0, flags=0) 用 pattern 对 strgin 进行分割,返回分割后剩下的子串组成的列表 Maxsplit:分割次数,即最多分割几次,默认0表示不限次数 如 re.split(r‘ ‘, r‘PYTHON is very easy!‘, 2) 返回 [‘PYTHON‘, ‘is‘, ‘very easy!‘] re.sub(pattern, repl, string, count=0, flags=0) 将 string 中匹配到 pattern 的内容替换为 repl,并返回替换之后的整个字符串,否则返回原字符串 string count:替换次数,默认0表示全部替换 如 re.sub(r‘PYTHON‘, r‘python‘, r‘PYTHON is very easy!‘) 返回 ‘python is very easy!‘ 如 re.sub(r‘Python‘, r‘python‘, r‘PYTHON is very easy!‘) 返回 ‘PYTHON is very easy!‘ re.escape(pattern) 对只有在正则表达式中具有特殊含义的字符的 pattern 进行转义,并返回转义后的 pattern 如 re.escape(‘http://www.python.org‘) 返回 ‘http://www\\.python\\.org‘
该模块提供了对 JSON 的支持,JSON 和 Python 之间的互相转换
JSON类型转Python类型的对应关系
JSON类型 |
Python类型 |
---|---|
object |
dict |
array |
list |
string |
str |
number (int) |
int |
number (real) |
float |
true |
True |
false |
False |
null |
None |
Python类型转JSON类型的对应关系
Python类型 |
JSON类型 |
---|---|
dict |
object |
list, tuple |
array |
str |
string |
int, float, int- & float-derived Enums |
number |
True |
true |
False |
false |
None |
null |
json.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw) 将 obj 转换成 JSON 字符串输出到 fp 流中 fp: 支持 write() 方法的文件 skipkeys: True表示跳过非基本类型(基本类型:str, int, float, bool, None)的 key,不引发 TypeError 异常,默认 False ensure_ascii: 默认True,输出中所有传入的非ASCII字符都已转义,False表示字符按原样输出 check_circula: False表示跳过对容器类型的循环引用检查,循环引用引发 OverflowError 异常,默认True allow_nan: False表示超出序列范围的 float(nan, inf, -inf) 将引发 ValueError 异常,默认True,使用其JavaScript等效项 (NaN,Infinity, -Infinity) indent: print()输出时的缩进级别,若为非负整数或字符串,则JSON数组元素和对象成员将使用该缩进级别进行打印,若为负数或""只会插入换行符 separators: 分隔符,二元元组,通常用于onj是字典类型,默认 (‘, ‘, ‘: ‘),第一个元素是行分隔符,第二个元素是key-value之间的分隔符 sort_keys: True表示字典输出按 key 排列,默认False json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw) 将 obj 转换成 JSON 字符串输出,参数和 json.dump() 一样 json.dumps([{‘a‘:1, ‘b‘:2, ‘c‘:3, ‘d‘:4, ‘e‘:5}])
json.load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) 从 fp 流读取 JSON 字符串,转化为 JSON 对象 json.loads(s, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) 将字符串 s 转化为 JSON 格式对应 Python 的类型 如 json.loads(‘["foo", {"bar":["baz", null, 1.0, 2]}]‘) 转化为列表类型 [‘foo‘, {‘bar‘: [‘baz‘, None, 1.0, 2]}]
原文:https://www.cnblogs.com/gudanaimei/p/13463769.html