Python学习日记8
开箱即用——模块与标准库10.1 模块的基本概念10.1.1 什么是模块模块Module就是一个.py文件包含 Python 代码。通过将代码组织成模块可以实现代码复用一个模块可以被多个程序导入使用命名空间隔离避免变量名冲突逻辑组织将相关功能放在一起# 创建一个简单的模块 hello.py # hello.py 内容 print(Hello, world!) def hello(name): print(fHello, {name}!)10.1.2 导入模块import hello # Hello, world!导入时自动执行模块代码 hello.hello(Alice) # Hello, Alice!10.1.3 模块只导入一次import hello # 不输出任何内容已导入过 # import 多次只执行一次模块代码为什么只导入一次性能优化避免重复解析和执行避免循环导入问题两个模块相互导入时第二次导入不会重新执行10.1.4 重新加载模块如果修改了模块代码可以使用importlib.reload()重新加载。import importlib hello importlib.reload(hello) # 重新执行模块代码10.1.5 模块搜索路径sys.pathPython 在以下位置查找模块import sys print(sys.path) # [, /usr/lib/python3.8, /usr/lib/python3.8/site-packages, ...]如何添加自定义路径sys.path.append(/path/to/my/modules)10.2 编写自己的模块10.2.1 模块就是程序任何.py文件都可以作为模块导入。# mymodule.py def greet(name): return fHello, {name}! print(Module loaded) # 导入时会执行import mymodule # Module loaded print(mymodule.greet(Alice)) # Hello, Alice!10.2.2 模块的测试代码if __name__ __main__当模块作为程序运行时__name__的值是__main__作为模块导入时__name__是模块名。# mymodule.py def greet(name): return fHello, {name}! def test(): print(greet(world)) # 只有当直接运行此文件时才执行测试 if __name__ __main__: test()执行效果# 直接运行 python mymodule.py # Hello, world! # 作为模块导入 python -c import mymodule # 无输出10.2.3 让模块可用方法1放在 site-packages 目录import sys print(sys.path) # 找到 site-packages 目录将模块复制进去方法2设置 PYTHONPATH 环境变量export PYTHONPATH/path/to/my/modules:$PYTHONPATH方法3动态添加到 sys.pathimport sys sys.path.append(/path/to/my/modules) import mymodule10.3 包Package10.3.1 什么是包包是包含多个模块的目录必须包含__init__.py文件。mypackage/ __init__.py # 包的初始化代码 module1.py module2.py subpackage/ __init__.py module3.py10.3.2 导入包中的模块# 导入整个包 import mypackage # 执行 __init__.py # 导入包中的模块 import mypackage.module1 from mypackage import module2 from mypackage.subpackage import module3 from mypackage.module1 import some_function10.4 探索模块10.4.1dir()—— 查看模块内容import copy print(dir(copy)) # [Error, __all__, __builtins__, ...]10.4.2__all__—— 定义公共接口# copy.py 中定义了 __all__ [Error, copy, deepcopy] from copy import * # 只导入 __all__ 中列出的名称10.4.3help()—— 获取帮助help(copy.copy) # 显示函数文档10.5 常用标准库10.5.1sys—— 系统相关示例处理命令行参数import sys # reverseargs.py反转并打印参数 args sys.argv[1:] args.reverse() print( .join(args))python reverseargs.py this is a test # test a is this10.5.2os—— 操作系统接口示例启动浏览器import os import webbrowser # 更好的选择 # 使用 os.system os.system(/usr/bin/firefox) # Linux os.system(rC:\Program Files\Mozilla Firefox\firefox.exe) # Windows # 更简单的方式webbrowser webbrowser.open(http://www.python.org)示例处理路径import os from pathlib import Path # 推荐用 pathlib # 传统方式 path os.path.join(folder, subfolder, file.txt) dir_name os.path.dirname(path) base_name os.path.basename(path) # 现代方式推荐 p Path(folder) / subfolder / file.txt print(p.parent) # folder/subfolder print(p.name) # file.txt10.5.3fileinput—— 迭代文件行示例给 Python 脚本添加行号import fileinput for line in fileinput.input(inplaceTrue): # inplace 就地修改 line line.rstrip() num fileinput.lineno() print({:50} # {:2d}.format(line, num))10.5.4 集合set创建集合# 从序列创建 s set([1, 2, 3, 1, 2]) # {1, 2, 3} # 字面量 s {1, 2, 3} # 空集合 s set() # {} 是空字典集合操作a {1, 2, 3} b {2, 3, 4} # 并集 a.union(b) # {1, 2, 3, 4} a | b # {1, 2, 3, 4} # 交集 a.intersection(b) # {2, 3} a b # {2, 3} # 差集 a.difference(b) # {1} a - b # {1} # 对称差集 a.symmetric_difference(b) # {1, 4} a ^ b # {1, 4} # 子集/超集 c {2, 3} c.issubset(a) # True a.issuperset(c) # True c a # True子集 c a # True真子集冻结集合frozenset不可变可用作字典键或集合元素。s frozenset([1, 2, 3]) d {s: value} # 可以作为键10.5.5 堆heapq堆是一种优先队列最小的元素总是在索引 0。from heapq import * from random import shuffle data list(range(10)) shuffle(data) heap [] for n in data: heappush(heap, n) print(heap) # [0, 1, 3, 6, 2, 8, 4, 7, 9, 5] print(heappop(heap)) # 0 print(heappop(heap)) # 110.5.6 双端队列collections.deque双端队列支持在两端高效地添加和删除元素。from collections import deque q deque(range(5)) print(q) # deque([0, 1, 2, 3, 4]) q.append(5) # 右端添加 q.appendleft(-1) # 左端添加 print(q) # deque([-1, 0, 1, 2, 3, 4, 5]) q.pop() # 右端弹出 → 5 q.popleft() # 左端弹出 → -1 q.rotate(3) # 向右旋转3步 print(q) # deque([2, 3, 4, 0, 1])对比列表10.5.7time—— 时间处理时间表示方式时间戳timestamp从 1970-01-01 00:00:00 UTC 开始的秒数时间元组struct_time包含 9 个字段的元组常用函数import time # 当前时间戳 timestamp time.time() # 1700000000.123 # 时间戳 → 时间元组本地时间 local time.localtime(timestamp) # 时间元组 → 字符串 time.asctime(local) # Tue Nov 14 10:30:00 2023 # 时间戳 → 字符串一次性 time.ctime(timestamp) # Tue Nov 14 10:30:00 2023 # 字符串 → 时间元组 time.strptime(2023-11-14, %Y-%m-%d) # 休眠 time.sleep(1) # 暂停1秒10.5.8random—— 随机数生成import random # 基本随机数 random.random() # 0.784... random.uniform(0, 10) # 6.234... random.randrange(1, 11) # 71~10之间的整数 # 序列操作 colors [red, green, blue] random.choice(colors) # green random.shuffle(colors) # [blue, red, green] random.sample(colors, 2) # [red, green]示例生成随机日期from random import uniform from time import mktime, localtime, asctime # 2016年内的随机时间 date1 (2016, 1, 1, 0, 0, 0, -1, -1, -1) date2 (2017, 1, 1, 0, 0, 0, -1, -1, -1) time1 mktime(date1) time2 mktime(date2) random_time uniform(time1, time2) print(asctime(localtime(random_time)))10.5.9shelve—— 持久化存储shelve提供了类似字典的接口但数据会保存到文件中。import shelve # 打开数据库 db shelve.open(mydata.db) # 像字典一样使用 db[name] Alice db[scores] [85, 92, 78] # 读取 print(db[name]) # Alice # 关闭 db.close()重要陷阱修改存储的对象需要重新赋值。db shelve.open(mydata.db) db[scores] [85, 92, 78] # 错误方式修改不会保存 db[scores].append(95) print(db[scores]) # [85, 92, 78]未保存 # 正确方式 scores db[scores] scores.append(95) db[scores] scores # 重新赋值才会保存 db.close()使用writebackTrue自动跟踪修改db shelve.open(mydata.db, writebackTrue) db[scores].append(95) # 自动保存 db.close()10.5.10json—— JSON 数据交换JSON 是跨语言的数据交换格式。import json # Python 对象 → JSON 字符串 data {name: Alice, age: 25, scores: [85, 92]} json_str json.dumps(data) print(json_str) # {name: Alice, age: 25, scores: [85, 92]} # JSON 字符串 → Python 对象 parsed json.loads(json_str) print(parsed[name]) # Alice # 读写文件 with open(data.json, w) as f: json.dump(data, f) with open(data.json, r) as f: loaded json.load(f)类型对照表10.5.11re—— 正则表达式常用函数基本语基本语法示例匹配邮件地址import re text From: Alice aliceexample.com To: Bob bobtest.org # 查找所有邮件地址 pattern r[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,} matches re.findall(pattern, text) print(matches) # [aliceexample.com, bobtest.org] # 使用分组提取用户名和域名 pattern r([a-zA-Z0-9._%-])([a-zA-Z0-9.-]\.[a-zA-Z]{2,}) for match in re.findall(pattern, text): print(fUser: {match[0]}, Domain: {match[1]})示例提取 HTML 标签内容html a href/jobs/1970/Python Engineer/a pattern re.compile(a href(/jobs/\\d)/(.*?)/a) for url, title in pattern.findall(html): print(f{title}: {url})贪婪 vs 非贪婪text *This* is *it*! # 贪婪模式匹配尽可能多 greedy r\*(.)\* print(re.sub(greedy, rem\1/em, text)) # emThis* is *it/em! # 非贪婪模式匹配尽可能少用 ? non_greedy r\*(.?)\* print(re.sub(non_greedy, rem\1/em, text)) # emThis/em is emit/em!10.6 其他有用的标准库