Python常用模块
内置函数
字符串
str.startswith()
str.startswith(prefix[, start[, end]]) -> bool
作用:判断字符串是否以指定 prefix 开头。
参数:
prefix可以是单个字符串,也可以是字符串组成的元组(tuple)——当是元组时,如果以 其中任意一个 前缀开头就返回 True。- 可选的 start、end 用来限定检查的切片范围
字典
dict.items()
将字典的每个键值对以元组的方式返回
dict.clear()
清空字典内容(清空本身,因为重新赋值有时候不适用)
dict.update(new_dict)
更新字典内容(即重新赋值)
列表
排序函数
list.sort()
list.sort(*, key=None, reverse=False)
作用:原地排序,只改变原列表顺序。返回值是 None
参数说明:
- key:应为一个可调用对象(如函数、lambda表达式)。Python会先对列表中的每个元素执行
key函数,生成一个键列表,再将键列表排序,最后根据键列表的顺序排列原列表 - reverse:是否降序排列。False->升序,True->降序
sorted()
sorted(iterable, *, key=None, reverse=False)
iterable:可迭代对象(列表、元组、字典、集合等)key:用于排序的函数(可调用对象),对每个元素先执行该函数reverse:是否降序排序
*后面的参数只能用关键字传
列表去重
set(list)->set
lst = [1, 2, 2, 3, 1]
new_lst = list(set(lst))#set()方法返回的是set对象,需要转为list
print(new_lst)
📌 特点
- 速度快
- 顺序会乱
- 只适用于 可哈希类型(int、str、tuple 等)
自己去重(保留原顺序)
lst = [1, 2, 2, 3, 1]
new_lst = []
seen = set()
for x in lst:
if x not in seen:
seen.add(x)
new_lst.append(x)
print(new_lst)
📌 特点
- 顺序不变
- 性能好(O(n))
- 推荐用于大多数场景
zip()
将两个可迭代对象一一配对成元组
示例:
blog_spider.urls = ["a.com", "b.com", "c.com"]
htmls = ["<html>...</html>", "<html>...</html>", "<html>...</html>"]
zip(blog_spider.urls, htmls)
结果会得到一个迭代器,内容相当于:
[
("a.com", "<html>...</html>"),
("b.com", "<html>...</html>"),
("c.com", "<html>...</html>")
]
得到的迭代器常用
list()转为列表,方便遍历
enumerate()
遍历列表(或其他可迭代对象)时,同时获取元素的索引和值
示例1:
for i, fruit in enumerate(fruits):
print(i, fruit)
示例2:转化成字典
lst = ["apple", "banana", "cherry"]
d = {i: fruit for i, fruit in enumerate(lst)}
print(d)
{0: 'apple', 1: 'banana', 2: 'cherry'}
urllib
常用方法:
- urllib.parse:
- unquote(data)
解码url编码的字符串from urllib.parse import unquote url = "https%3A%2F%2Fwww.example.com%2Fpath%3Fquery%3Dpython" decoded_url = unquote(url)
- unquote(data)
argparse
简介:argparse 模块是 Python 内置的用于命令项选项与参数解析的模块,argparse 模块可以让人轻松编写用户友好的命令行接口,能够帮助程序员为模型定义参数。
人话:定义命令行参数
常用方法
- argparse.ArgumentParser()
创建ArgumentParser()对象parser = argparse.ArgumentParser()-
.add_argument:给一个 ArgumentParser 对象添加程序参数信息
1.基本位置参数
#test.py import argparse parser = argparse.ArgumentParser() parser.add_argument('filename', help='要处理的文件') args = parser.parse_args() print(f"基本位置参数:{args.filename}")运行测试:
$ python test.py a.txt 基本位置参数:a.txtfilename为基本位置参数名,可自定义。
调用时通过调用args.基本位置参数名来实现注:
- 基本位置参数对定义顺序敏感,会严格按照定义顺序来解析
- 直接写值,无前缀
- 该参数定义后必须提供
2.可选参数
import argparse parser = argparse.ArgumentParser() parser.add_argument("-i","--input",help="输入") args = parser.parse_args() print(f"输入文件{args.input}")运行测试:
$ python -i abcd.txt 输入文件abcd.txt
短参数一般由
-加上一个字母组成,长参数一般由--加上一个单词组成
注:
- 短参数与长参数的参数名可以自定义
- 短参数是可选的,长参数是必须的。在调用参数时只能调用长参数而无法调用短参数
- 可以通过
python test.py -h来查看help的信息
3.动作(action)
3.1
action参数概述action 参数指定了当命令行参数被解析时应采取的行为,它控制着如何存储参数值。如果不指定 action,默认是 'store'
3.2 所有可用的
action类型- store(默认值):
作用:存储参数的值
特点:- 需要一个值参数
- 将提供的值存储到
args对象中
示例:
import argparse parser = argparse.ArgumentParser() parser.add_argument("--input",action="store",help="输入") args = parser.parse_args() print(f"输入文件{args.input}")运行测试:
$ python test.py --input abcd.txt 输入文件abcd.txt- store_const
作用:存储一个常量
特点:- 不需要值参数
- 必须配合
const参数使用 - 当参数出现时存储
const值
示例:
import argparse parser = argparse.ArgumentParser() parser.add_argument("--input",action="store_const",const=1234,default=9999,help="输入") args = parser.parse_args() print(f"常量:{args.input}")运行测试
└─$ python test.py --input 常量:1234 └─$ python test.py 常量:9999注:
- action类型若选为该类型则不能传值
- 在选择该选项时,值为const的值;未选择时,值为default的值
- store_true/store_false:
作用:store_const的特例版本
特点: - store_true:参数出现时存储 True
- store_false:参数出现时存储 False
- 不需要指定 const
示例:
import argparse parser = argparse.ArgumentParser() parser.add_argument("--input",action="store_true",default=9999,help="输入") args = parser.parse_args() print(f"常量:{args.input}")运行测试:
$ python test.py --input 常量:True $ python test.py 常量:9999- append
作用:将多个参数值整理成列表
特点: - 每次出现参数时,将值追加到列表
- 该参数允许多次使用
示例:
import argparse parser = argparse.ArgumentParser() parser.add_argument("--input",action="store_true",default=9999,help="输入") parser.add_argument("-a","--add",action="append",help="将多个参数收集成列表") args = parser.parse_args() print(f"列表:{args.add}")运行测试:
$ python test.py -a 1.c -a 2.c 列表:['1.c', '2.c']- append_const:
作用:将常量值追加到列表
特点: - 必须配合
const参数使用 - 每次出现该参数时,将
const值追加到列表
示例:
import argparse parser = argparse.ArgumentParser() parser.add_argument("--input",action="store_true",default=9999,help="输入") parser.add_argument("-a","--add",action="append_const",const="active",help="将多个参数收集成列表") args = parser.parse_args() print(f"列表:{args.add}")运行测试:
$ python test.py -a -a -a 列表:['active', 'active', 'active']- count
作用:计算参数出现的次数
特点: - 不需要值参数
- 每次出现参数时,计时器+1
示例:
import argparse parser = argparse.ArgumentParser() parser.add_argument("--input",action="store_true",default=9999,help="输入") parser.add_argument("-a","--add",action="append_const",const="active",help="将多个参数收集成列表") parser.add_argument("-v","--verbose",action="count",default=0,help="计数") args = parser.parse_args() print(f"计数:{args.verbose}")运行测试:
$ python test.py 计数:0 $ python test.py -v 计数:1 $ python test.py -vvv 计数:3- help
作用:显示帮助信息并退出
特点: - 自动添加
-h/--help参数 - 通常不需要手动添加
示例:
parser.add_argument('--help', action='help', help='显示帮助信息')运行测试
$ python script.py --help # 显示帮助信息并退出- version
作用:显示版本信息并退出
特点: - 必须配合
version参数使用 - 适合显示版本信息
示例:
import argparse parser = argparse.ArgumentParser() parser.add_argument("--input",action="store_true",default=9999,help="输入") parser.add_argument("-a","--add",action="append_const",const="active",help="将多个参数收集成列表") parser.add_argument("-v","--verbose",action="count",default=0,help="计数") parser.add_argument("--version",action="version",version="1.0.0",help="显示版本信息") args = parser.parse_args() print(f"版本信息:{args.version}")运行测试:
$ python test.py --version 1.0.03.3 使用建议
场景 选择 开关选项: 使用 store_true/store_false 最方便 多值收集: 使用 append 或 append_const 详细级别: count 是理想选择 版本信息: 使用 version 自动处理 常量存储: store_const 适合固定值场景 4.参数数量(nargs)
指定参数接收值的数量:
N:接收N个值?:接收0或1个值*:接收0或多个值+:接收1或多个值
示例:
parser.add_argument('files', nargs='+') # 至少一个文件名 parser.add_argument('--input', nargs=2) # 需要两个值5.常量值(const)
某些动作需要配合常量值使用
示例:parser.add_argument('--mode', action='store_const', const='debug')6.默认值(default)
当未提供参数时的默认值
示例:parser.add_argument('--port', default=8000)7.参数类型(type)
将输入参数转化为指定类型
示例:parser.add_argument('--port', type=int) parser.add_argument('--file', type=argparse.FileType('r'))8.选择范围(choices)
限制参数值为给定集合中的值
示例:parser.add_argument('--color', choices=['red', 'green', 'blue'])9.帮助信息(help)
参数的描述信息(输入
-h时展示)
示例:parser.add_argument('--input', help='输入文件路径')10.参数组(metavar)
在帮助信息中显示的参数名称
示例:import argparse parser = argparse.ArgumentParser() parser.add_argument("--input",action="store_true",default=9999,help="输入") parser.add_argument("-a","--add",action="append_const",const="active",help="将多个参数收集成列表") parser.add_argument("-v","--verbose",action="count",default=0,help="计数") parser.add_argument("--version",action="version",version="1.0.0",help="显示版本信息") parser.add_argument("-f","--file",metavar="FILE_INPUT") args = parser.parse_args() print(f"版本信息:{args.version}")运行测试:
$ python test.py -h usage: test.py [-h] [--input] [-a] [-v] [--version] [-f FILE_INPUT] options: -h, --help show this help message and exit --input 输入 -a, --add 将多个参数收集成列表 -v, --verbose 计数 --version 显示版本信息 -f FILE_INPUT, --file FILE_INPUT11.必需参数 (required)
对于可选参数,是否必须提供
示例:parser.add_argument('--input', required=True)12.目标属性名(dest)
自定义该参数被引用时的属性名
示例:import argparse parser = argparse.ArgumentParser() parser.add_argument("--input",action="store_true",default=9999,help="输入") parser.add_argument("-a","--add",action="append_const",const="active",help="将多个参数收集成列表") parser.add_argument("-v","--verbose",action="count",default=0,help="计数") parser.add_argument("--version",action="version",version="1.0.0",help="显示版本信息") parser.add_argument("-f","--file",metavar="FILE_INPUT") parser.add_argument("-o","--output",action="store_const",const="该参数已被选中",dest="out") args = parser.parse_args() # print(f"版本信息:{args.version}") print(args.out) #这里被指定为out,而不是默认的output运行测试:
$ python test.py -o 该参数已被选中
-
threading
多线程
常用方法
- 创建线程
def server():
pass
mqtt_thread = threading.Thread(target=server)#把整个示例作为封装成一个函数传递给线程
mqtt_thread.start()#启动线程
- 结束线程:使用 threading.Event() 控制线程退出
import threading
import time
# 创建 Event 对象
stop_event = threading.Event()
def worker():
while not stop_event.is_set():
print("Thread is running...")
time.sleep(1)
print("Thread stopped.")
# 启动线程
thread = threading.Thread(target=worker)
thread.start()
# 5秒后触发停止
time.sleep(5)
stop_event.set() # 设置事件,通知线程停止
thread.join() # 等待线程结束
print("Main thread exits.")
- is_alive()检查线程是否已启动
import threading
import time
def worker():
print("Thread working...")
time.sleep(2)
# 创建线程
thread = threading.Thread(target=worker)
# 检查线程状态
print("Before start:", thread.is_alive()) # False
# 启动线程
thread.start()
# 再次检查
print("After start:", thread.is_alive()) # True
# 等待线程结束
thread.join()
print("After join:", thread.is_alive()) # False
说明:
- stop_event.is_set() 检查是否被触发。
- stop_event.set() 通知线程停止。
- 比全局变量更安全,适用于更复杂的多线程场景。
注:多个线程之间共用全局变量资源
- 主线程退出时结束子线程
thread = threading.Thread(target=window_monitor, args=(self.tableWidget,))
thread.daemon = True # 主线程退出时自动结束
thread.start()
Lock线程锁
使用情景
线程安全产生的原因:假设有线程1和线程2同时取800元(共有存款1000元)
def draw(account,amount):
if account.balance >= amount: # 存款比取的钱多
account.balance -= amount # 取款成功
当线程1取钱刚通过了if判断,但是还没有执行取款操作时,此时的存款仍为1000元。而这时线程2参与进来,也通过了if判断,就会导致两个线程都可以取款成功。金额变为了-600元。
解决方法:
对这块代码进行加锁。
用法1:try-finally模式(手动加锁并释放)
import threading
lock = threading.Lock() # 获取锁对象
lock.acquire() # 加锁
try:
#do something
finally:
lock.release() # 释放锁
用法2:with模式(自动加锁)
import threading
lock = threading.Lock()
with lock:
# do something
注意:锁要共享才能避免竞争。自己锁自己没用
正确示例:共享锁
import threading
import time
lock = threading.Lock() # 新建一把锁,应为共享使用一把,才能防止竞争
class Account:
def __init__(self,balance):
self.balance = balance
def draw(account,amount):
with lock:
if account.balance >= amount:
time.sleep(0.1)
print(threading.current_thread().name,"取钱成功")
account.balance -= amount
print(threading.current_thread().name,"余额",account.balance)
else:
print(threading.current_thread().name,"取钱失败,余额不足")
if __name__ == "__main__":
account = Account(1000)# 初始化有1000元
ta = threading.Thread(name="tA",target=draw,args=(account,800))
tb = threading.Thread(name="tB",target=draw,args=(account,800))
ta.start()
tb.start()
错误示例:自己锁自己,没人竞争
import threading
import time
class Account:
def __init__(self,balance):
self.balance = balance
def draw(account,amount):
lock = threading.Lock() # 每次都新建一把锁,自己锁自己,没人竞争
with lock:
if account.balance >= amount:
print(threading.current_thread().name,"取钱成功")
account.balance -= amount
print(threading.current_thread().name,"余额",account.balance)
else:
print(threading.current_thread().name,"取钱失败,余额不足")
if __name__ == "__main__":
account = Account(1000)# 初始化有1000元
ta = threading.Thread(name="tA",target=draw,args=(account,800))
tb = threading.Thread(name="tB",target=draw,args=(account,800))
ta.start()
tb.start()
常用方法
- .acquire()/.release() 获取与释放锁
lock.acquire() # 获取锁
# 临界区(critical section)——此处的代码只能由一个线程执行
lock.release() # 释放锁
注意
time.sleep(0.1)会使当前线程阻塞,并切换线程
import threading
import time
class Account:
def __init__(self,balance):
self.balance = balance
def draw(account,amount):
if account.balance >= amount:
time.sleep(0.1) #在此切换线程,使另一个线程也能通过if语句
print(threading.current_thread().name,"取钱成功")
account.balance -= amount
print(threading.current_thread().name,"余额",account.balance)
else:
print(threading.current_thread().name,"取钱失败,余额不足")
if __name__ == "__main__":
account = Account(1000)# 初始化有1000元
ta = threading.Thread(name="tA",target=draw,args=(account,800))
tb = threading.Thread(name="tB",target=draw,args=(account,800))
ta.start()
tb.start()
此时会一直出现bug
tA 取钱成功
tA 余额 200
tB 取钱成功
tB 余额 -600
- 采用多线程时,一条线程为更新字典的函数,一条线程为把字典保存为json文件的函数。会不会出现只保存了一部分就突然切换线程更新字典的情况
完全有可能,而且这是 典型的多线程竞态问题
结果可能出现:
- JSON 文件只包含部分更新(部分写入前被修改了)。
- 写入过程中字典被修改,可能抛出 RuntimeError: dictionary changed size during iteration(如果你在保存时遍历字典)。
解决方案:使用线程锁
import threading
import json
data = {}
lock = threading.Lock()
def update_dict():
while True:
with lock: # 加锁
data['key'] = data.get('key', 0) + 1
# 模拟每秒更新
time.sleep(1)
def save_dict_to_json():
while True:
with lock: # 加锁,确保写入期间字典不被修改
with open('data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
time.sleep(5)
with lock: 保证在修改或写入字典时,同一时间只有一个线程访问字典。- 保存 JSON 时锁住,避免更新线程在写入过程中修改字典。
json模块
常用方法
- .load:对文件中的数据进行解码
- .loads:对数据进行解码
- .dump:将数据编码并保存成文件
- .dumps:可以对数据进行编码
注:json与标准python字典并不完全一致
{"status": "success"} // ✅ 正确
{'status': 'success'} // ❌ 错误
json对于字符串必须采用严格的双引号,因此从别处接收到json信息时,需要先转换成python字典,再转换成json格式进行校验
注:json.load(file) 其中file参数应该是一个文件对象,而不是文件路径
with open("./noteWeb/config.json", "r") as f:
config = json.load(f)
方法详解
dump()
json.dump(data, f, ensure_ascii=False, indent=4)
- data:要转化成json的Python数据对象
- f:一个已打开的文件对象
- ensure_ascii:
- True(默认值):所有非 ASCII 字符(比如中文)都会被转义成
\uXXXX形式 - False:直接输出原始字符(方便阅读中文)。
- True(默认值):所有非 ASCII 字符(比如中文)都会被转义成
- indent:控制 JSON 的缩进层级,使输出更漂亮、可读性更高。
indent=4 表示每一层缩进 4 个空格。
如果不加 indent,输出会是一行压缩格式。
ThreadPoolExecutor 线程池
导入模块
from concurrent.futures import ThreadPoolExecutor,as_completed
用法1:map函数
with ThreadPoolExecutor() as pool:
results = pool.map(函数名,参数列表)
for result in results:
print(result)
注:map的结果和入参是顺序对应的
用法2:future模式,更强大
with ThreadPoolExecutor() as pool:
futures = [pool.submit(craw,url) for url in urls] #craw为函数名,url为参数列表
# 遍历方法1:根据url的顺序挨个返回(即使url未加载完也等待)
for future in futures:
print(future.result())
# 遍历方法2:哪个url先解析完就先返回哪个
for future in as_completed(futures):
print(future.result())
注:如果用as_completed顺序是不定的
queue
线程安全
适用于多线程同步任务
支持同步阻塞
常用方法
1.创建队列
import queue
# 默认 FIFO 队列,容量无限制
q = queue.Queue(maxsize=10)
2.入队与出队
# 入队(阻塞操作)
q.put(item) # 阻塞至有空位
q.put_nowait(item) # 非阻塞,队列满时抛出 queue.Full 异常
# 出队(阻塞操作)
item = q.get() # 阻塞至有数据
item = q.get_nowait()# 非阻塞,队列空时抛出 queue.Empty 异常
3.队列状态检查
q.empty() # 返回队列是否为空(非线程安全,结果可能不可靠)
q.full() # 返回队列是否已满
q.qsize() # 返回队列当前元素数量(非线程安全)
4.任务完成追踪
q.task_done() # 标记一个任务完成(需与 get() 成对调用)
q.join() # 阻塞主线程,直到所有任务被处理完毕
5.队空报错
try:
# 添加超时,避免永久阻塞
msg = q.get(timeout=1.0)
yield f"data: {json.dumps(msg)}\n\n"
except queue.Empty:
# 发送心跳保持连接
yield ": heartbeat\n\n"
.Queue 默认队列,先进先出
.LifoQueue 后进先出,模拟栈结构。
.PriorityQueue 按优先级排序,元素需为可比较元组。
示例:优先级队列
pq = queue.PriorityQueue()
pq.put((3, "低优先级任务")) # 元组格式:(优先级, 数据)
pq.put((1, "高优先级任务")) # 优先级数值越小越优先
注:通过.get()方法出队的元素为二进制编码,恢复编码格式可能需要.decode("utf-8)
psutil 进程
常用方法
import psutil
# 获取当前进程
current_process = psutil.Process()
# 获取进程ID
print(f"PID: {current_process.pid}")
# 获取进程名称
print(f"Name: {current_process.name()}")
# 获取进程状态
print(f"Status: {current_process.status()}")
# 获取CPU使用率
print(f"CPU %: {current_process.cpu_percent(interval=1.0)}")
# 获取内存信息
print(f"Memory Info: {current_process.memory_info()}")
# 获取打开的连接
print(f"Connections: {current_process.connections()}")
# 获取线程信息
print(f"Threads: {current_process.threads()}")
获取所有进程
psutil.process_iter(['pid', 'name', 'username', 'status'])#返回值是一个可迭代的对象,其中每一个元素都是一个进程
示例
import psutil
# 遍历所有进程
for proc in psutil.process_iter(['pid', 'name', 'username', 'status']):
try:
# 获取进程详情
process_info = proc.as_dict(attrs=['pid', 'name', 'cpu_percent', 'memory_info'])
print(process_info)
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
# 处理可能出现的异常
pass
获取特定信息示例
import psutil
# 获取所有进程的名称和PID
process_list = []
for proc in psutil.process_iter(['pid', 'name']):
process_list.append(proc.info)#proc.info 将主要信息转化成字典{'pid': 0, 'name': 'System Idle Process'}
print("所有进程列表:")
for process in process_list:
print(f"PID: {process['pid']}, 名称: {process['name']}")
time 时间处理
一、模块介绍
Python的Time库用于时间相关处理,包括:
- 访问当前日期和时间
- 输出不同格式的时间
- 等待指定时间
二、常用方法
1. time.time()
返回当前时间戳(从1970-01-01 00:00:00 UTC开始的秒数)
>>> import time
>>> time.time()
1663950612.3896797
tm_year: 年
tm_mon: 月,范围为[1,12]
tm_mday: 一个月的第几天,范围为[1,31]
tm_hour: 小时,范围为[0,23]
tm_min: 分, 范围为[0,59]
tm_sec: 秒,范围为[0,59]
tm_wday: 一周中的第几天,范围是[0,6],周一为0
tm_yday: 一年中的第几天,范围是[1,366]
tm_isdat: 1代表夏令时
2. time.localtime([sec])
将时间戳转换为时间元组,不加参数返回当前时间
格式:(tm_year,tm_mon,tm_mday,tm_hour,tm_min,tm_sec,tm_wday,tm_yday,tm_isdst)
>>> time.localtime()
time.struct_time(tm_year=2022, tm_mon=9, tm_mday=24, tm_hour=0, tm_min=48, tm_sec=28, ...)
>>> time.localtime().tm_year # 访问单个元素
2022
参数填秒数
3. time.gmtime([sec])
返回UTC时间(0时区)的时间元组
>>> time.gmtime() # 与localtime()时区不同
该时间元组从0开始,而非1970
4. time.ctime([sec])
将时间戳转换为字符串格式
>>> time.ctime()
'Sat Sep 24 00:55:07 2022'
5. time.asctime([tuple])
将时间元组转换为字符串格式
>>> time.asctime()
'Sat Sep 24 01:09:14 2022'
6. time.mktime(tuple)
将时间元组转换为时间戳
>>> time.mktime(time.localtime())
1663953237.0
7. time.strftime(format [,tuple])
定制化输出时间字符串
格式控制符:
%Y-年 %m-月 %d-日 %H-时(24) %M-分 %S-秒
%B-月份全称 %b-月份简称
%A-星期全称 %a-星期简称
%p-AM/PM
>>> time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
'2022-09-24 01:42:10'
8. time.strptime(str, format)
将字符串解析为时间元组
>>> time.strptime('2011-09-11 08:40:22', "%Y-%m-%d %H:%M:%S")
需要传入完整的时间字符串,且时间不能小于1970
9. time.sleep(sec)
程序暂停指定秒数
>>> time.sleep(1) # 等待1秒
>>> time.sleep(0.5) # 等待0.5秒
三种时间格式
- 时间戳(timestamp)
- 时间元组(struct_time)
- 时间字符串(formatted string)
ctypes 系统弹窗(仅限Windows)
常用方法
import ctypes
ctypes.windll.user32.MessageBoxW(0, "这是一个弹窗", "标题", 0x40) # 0x40 是信息图标
subprocess shell命令函数
专门执行调用shell命令,回显等功能的模块
基本用法
def send(topic:str,send_data:dict):
args=["python3","./mqtt-server/sendjson.py"]
args.append(topic)
args.append(json.dumps(send_data))
shell = subprocess.run(args=args,capture_output=True, text=True)
print(shell.stdout)#打印标准输出
print(shell.stderr)#打印错误输出
random 随机数库
(1) 生成基础随机数
| 函数名 | 描述 | 示例 |
|---|---|---|
| random() | 返回 [0, 1) 之间的浮点数 | print(random()) → 0.5488135 |
| randint(a, b) | 返回 [a, b] 闭区间内的整数 | print(randint(1, 10)) → 7 (含10) |
| randrange(start, stop[, step]) | 返回 start 到 stop(不含)间按 step 步长的整数 | print(randrange(0, 10, 3)) → 3 或 6 或 9 |
(2) 生成随机分布数值
| 函数名 | 描述 | 示例 |
|---|---|---|
| random.uniform(a, b) | 返回 [a, b] 或 [b, a] 间的浮点数(均匀分布) | print(uniform(1, 5)) → ~2.345 |
| random.gauss(mu, sigma) | 生成均值为 mu、标准差为 sigma 的正态分布浮点数 | print(gauss(0, 1)) → ~0.432 |
(3) 随机选择元素
| 函数名 | 描述 | 示例 |
|---|---|---|
| random.choice(seq) | 从序列(可迭代对象)中随机选择一个元素 | lst = [1,2,3]; print(choice(lst)) → 2 |
| random.sample(population, k) | 从 population 中不重复地抽取 k 个元素 | lst = [1,2,3,4]; print(sample(lst, 2)) → [1,3] |
(4) 打乱顺序
| 函数名 | 描述 | 示例 |
|---|---|---|
| random.shuffle(seq) | 将原列表 seq 的顺序随机打乱(原地操作) | lst = [1,2,3]; shuffle(lst); print(lst) → [3,1,2] |
(5) 其他实用函数
| 函数名 | 描述 | 示例 |
|---|---|---|
| random.getrandbits(n) | 生成 n 位的随机整数(二进制位) | print(getrandbits(4)) → 10 (二进制 1010) |
| random.system_random() | 获取操作系统提供的加密安全随机数生成器(Python 3.6+弃用) 替代方案:使用 secrets 模块 |
Python os 模块核心方法摘要
os 模块提供了丰富的方法用于与操作系统进行交互,特别是文件系统、进程和环境变量等。
一、 文件和目录操作
os.rename(src, dst)
重命名文件或目录。
os.remove(path)
os.unlink(path)
删除一个文件。
os.rmdir(path)
删除一个空目录。
os.mkdir(path[, mode])
创建一个目录。
os.makedirs(name, mode=0o777, exist_ok=False)
#exist_ok=False (默认值):如果 name 指定的目录已经存在,Python 会抛出一个 FileExistsError 异常。
#exist_ok=True:如果目录已存在,函数不会做任何事情,也不会报错,静默成功。这是非常实用的一个参数。
递归创建目录(创建中间级目录)。
os.listdir(path='.')
返回指定路径下的文件和目录名列表。
os.scandir(path='.')
返回一个包含 DirEntry 对象的迭代器,性能优于 listdir(推荐用于遍历目录)。
os.walk(top)
生成目录树中的文件名,用于遍历所有子目录。
os.chdir(path)
改变当前工作目录。
os.getcwd()
返回当前工作目录的路径。
os.stat(path)
获取文件或文件描述符的状态信息(大小、修改时间等)。
二、 路径操作 (通常更推荐使用 os.path 子模块)
os.path.join(path1[, path2[, ...]])
智能地拼接一个或多个路径组件。
os.path.abspath(path)
返回路径的绝对路径。
os.path.basename(path)
返回路径中的文件名部分。
os.path.dirname(path)
返回路径中的目录部分。
os.path.exists(path)
判断路径(文件或目录)是否存在。
os.path.isfile(path)
判断路径是否为文件。
os.path.isdir(path)
判断路径是否为目录。
os.path.split(path)
将路径分割为 (目录, 文件名) 的元组。
os.path.splitext(path)
将路径分割为 (root, ext) 的元组,其中 ext 是扩展名。
三、 进程管理
os.system(command)
在子 shell 中执行操作系统命令(字符串)。
os.popen(cmd[, mode[, bufsize]])
打开一个与命令 cmd 的管道(已过时,推荐 subprocess 模块)。
os.fork()
创建一个子进程(仅在 Unix/Linux 系统可用)。
os.kill(pid, sig)
发送一个信号 sig 给进程 pid。
os.getpid()
返回当前进程的 ID。
os.getppid()
返回父进程的 ID。
四、 环境变量
os.environ
一个表示环境变量的映射对象。
os.getenv(key, default=None)
获取指定环境变量的值。
os.putenv(key, value)
设置环境变量(但直接修改 os.environ 更推荐)。
五、 文件描述符操作 (底层 I/O)
os.open(file, flags[, mode])
打开一个文件,返回文件描述符(低级操作)。
os.close(fd)
关闭文件描述符 fd。
os.read(fd, n)
从文件描述符 fd 中读取最多 n 个字节。
os.write(fd, str)
将字符串(或字节串)写入文件描述符 fd。
六、 其他杂项
os.name
返回导入模块依赖的操作系统名称(如 'posix', 'nt', 'java')。
os.sep
输出操作系统特定的路径分隔符(Windows 是 \,Linux/macOS 是 /)。
os.linesep
输出当前平台使用的行终止符(Windows 是 \r\n,Linux 是 \n,macOS 是 \n)。
os.urandom(n)
返回一个包含 n 个字节的随机字符串,适合加密使用。
python-magic 识别文件头、识别文件真实类型
安装
pip install python-magic
使用示例
import magic
file_path = "example.png"
mime_type = magic.from_file(file_path, mime=True) # 返回 MIME 类型
print("MIME类型:", mime_type)
file_type = magic.from_file(file_path) # 返回更详细的描述
print("文件类型描述:", file_type)
输出:
MIME类型: image/png
文件类型描述: PNG image data, 800 x 600, 8-bit/color RGB
注:在 Windows 上需要额外安装
libmagic支持,可以使用python-magic-bin
pip install python-magic-bin
MIME类型: image/png
MIME类型: image/jpeg
常见函数
| 函数 / 方法 | 作用 | 常用场景 |
|---|---|---|
magic.from_file(path, mime=False) |
根据文件路径识别文件类型 | 直接检测本地文件 |
magic.from_buffer(buffer, mime=False) |
根据字节内容识别文件类型 | 适用于上传文件、内存中的数据流 |
magic.Magic() |
创建一个自定义检测对象,可反复使用 | 高级用法,性能更好 |
magic.open(flags) (旧接口) |
较旧的接口形式,一般不推荐使用 | 兼容旧代码 |
magic.Magic(mime=True) |
只返回 MIME 类型字符串 | 常用于安全检测(如 image/jpeg) |
pathlib 用“面向对象”的方式操作文件系统路径,取代传统的 os.path。
常用功能
from pathlib import Path
# 读取所有行到列表(适合小文件)
# 文件不存在时不能自动创建
lines = Path(r'群内代码测试\201-300\file.txt').read_text().splitlines()
# 修改特定行
lines.append("新增1行内容\n")
# lines[0] = "修改第1行内容\n" # 注意索引从0开始
# 写回文件
Path(r'群内代码测试\201-300\file.txt').write_text(''.join(lines),encoding="utf-8")
核心对象Path
Path 是最重要的类,它表示一个文件或目录的路径。
from pathlib import Path
p = Path("/var/www/media/icon.png")
常用方法
- 基本属性
p = Path("/home/user/docs/file.txt")
p.name # 'file.txt' —— 文件名(含扩展名)
p.stem # 'file' —— 不含扩展名的文件名
p.suffix # '.txt' —— 文件扩展名
p.suffixes # ['.tar', '.gz'] —— 复合扩展名时使用
p.parent # Path('/home/user/docs') —— 上级目录
p.parents[1] # Path('/home/user')
p.anchor # '/' —— 根路径
注:不能使用Linux的
~
- 路径拼接(
/操作符被重载,用来拼接路径:)
base = Path("/var/www")
file = base / "media" / "icon.png"
print(file) # /var/www/media/icon.png
- 路径判断
p.exists() # 是否存在
p.is_file() # 是否为文件
p.is_dir() # 是否为目录
p.is_absolute() # 是否为绝对路径
- 路径解析与规范化
p.resolve() # 返回绝对路径(会解析符号链接)
p.absolute() # 仅返回绝对路径,不解析符号链接
安全场景常用(防止目录穿越攻击):
base = Path("/var/www/media").resolve()
target = (base / "../etc/passwd").resolve()
示例:
from pathlib import Path
base = Path(base_dir).resolve()
target = Path(file_path).resolve()
# Python 3.9+ 提供 is_relative_to
if not target.is_relative_to(base):
# 拒绝
- 路径组合与分解
p = Path("/home/user/docs/file.txt")
p.with_name("new.txt") # /home/user/docs/new.txt
p.with_suffix(".jpg") # /home/user/docs/file.jpg
p.joinpath("sub", "a.txt") # /home/user/docs/sub/a.txt
- 文件操作(直接读写)
p = Path("test.txt")
p.write_text("Hello world!") # 写入文本
text = p.read_text() # 读取文本
p.write_bytes(b"data") # 写入二进制
data = p.read_bytes() # 读取二进制
也可以直接打开
with p.open("r", encoding="utf-8") as f:
print(f.read())
- 遍历目录
p = Path("/var/www/media")
for child in p.iterdir(): # 只遍历一层
print(child)
for file in p.rglob("*.png"): # 递归遍历所有 .png 文件
print(file)
- 创建、删除路径
p = Path("data/new_folder")
p.mkdir(parents=True, exist_ok=True) # 创建目录
#parents=True:如果父目录不存在则一并创建。
#exist_ok=True:如果目录存在不会报错
p.rmdir() # 删除空目录
- 路径比较与关系判断(防目录穿越)
base = Path("/var/www/media").resolve()
target = Path("/var/www/media/user/a.png").resolve()
# 判断是否在子目录内(Python 3.9+)
target.is_relative_to(base) # True
# 等价写法(兼容老版本)
try:
target.relative_to(base)
print("在子目录内")
except ValueError:
print("不在子目录内")
- 常用技巧
| 目的 | 示例 |
|---|---|
| 获取当前工作目录 | Path.cwd() |
| 获取脚本所在目录 | Path(__file__).parent |
| 临时拼接路径 | (Path.cwd() / "temp").mkdir(exist_ok=True) |
| 替换文件扩展名 | p.with_suffix(".jpg") |
| 递归查找图片 | for f in Path("media").rglob("*.png"): |
| 安全防护 | target.resolve().is_relative_to(base.resolve()) |
pygetwindow 获取和控制桌面应用窗口信息
它可以枚举桌面上已有的窗口、按标题查找窗口,并能对窗口执行诸如激活、最小化、最大化、移动、调整大小等操作
安装
pip install pygetwindow
注:在Windows上最完整、可靠。其他系统只能使用部分方法或完全不可用
一、模块级函数(用于全局窗口操作)
| 函数名 | 说明 |
|---|---|
| getAllTitles() | 获取所有窗口标题的字符串列表。 |
| getAllWindows() | 获取所有窗口对象(Window 实例) |
| getWindowsWithTitle(title, exact=False) | 根据窗口标题匹配返回窗口对象列表 |
| getWindowsAt(x, y) | 获取屏幕坐标 (x, y) 处的窗口对象 |
| getActiveWindow() | 获取当前活动窗口对象 |
| getActiveWindowTitle() | 获取当前活动窗口的标题 |
| getFocusedWindow() | (部分版本)同上,返回当前焦点窗口对象 |
注:getAllTitles()等方法可能会得到一些空字符串,需要过滤。这是由于一些隐藏窗口(如系统隐藏窗口、输入法等窗口没有标题导致的)
二、Window 对象属性
| 属性名 | 说明 |
|---|---|
| title | 窗口标题 |
| left | 窗口左上角 X 坐标 |
| top | 窗口左上角 Y 坐标 |
| width | 窗口宽度 |
| height | 窗口高度 |
| size | (width, height) 元组 |
| topleft | (left, top) 元组 |
| bottomright | 窗口右下角坐标元组 |
| isMaximized | 是否已最大化 |
| isMinimized | 是否已最小化 |
| isActive | 是否为活动窗口 |
| isVisible | 是否可见 |
三、Window 对象方法
| 方法名 | 说明 |
|---|---|
| activate() | 激活窗口,使其成为前台窗口 |
| bringToFront() | 将窗口置于最前 |
| minimize() | 最小化窗口 |
| maximize() | 最大化窗口 |
| restore() | 从最小化/最大化状态恢复窗口 |
| moveTo(x, y) | 移动窗口到指定位置 |
| move(dx, dy) / moveRel(dx, dy) | 相对移动窗口 |
| resizeTo(width, height) | 调整窗口大小到指定值 |
| resize(dw, dh) / resizeRel(dw, dh) | 相对调整窗口大小 |
| close() | 关闭窗口 |
四、常用函数分类
以下是最常用、最实用的函数与方法:
| 类型 | 函数/方法 | 功能描述 |
|---|---|---|
| 获取窗口 | getAllWindows() | 获取所有窗口对象 |
| 获取标题 | getAllTitles() | 获取所有窗口标题 |
| 查找窗口 | getWindowsWithTitle(title) | 按标题匹配查找窗口 |
| 当前窗口 | getActiveWindow() | 获取当前活动窗口 |
| 激活窗口 | Window.activate() | 将窗口置前并激活 |
| 移动窗口 | Window.moveTo(x, y) | 移动窗口位置 |
| 调整大小 | Window.resizeTo(width, height) | 改变窗口大小 |
| 状态控制 | Window.minimize() / Window.maximize() / Window.restore() | 控制窗口显示状态 |
| 关闭窗口 | Window.close() | 关闭窗口 |
PyQt5Designer pyqt5的图形化操作工具
pip install PyQt5Designer
详见pyqt5分区的专门的笔记
PyInstaller 一键打包exe
常用参数说明
-h或--help:显示帮助信息,列出所有可用参数及其说明。-D:生成一个目录,包含可执行文件和所有依赖的库文件。(默认打包方式)-F:生成一个单个的可执行文件,包含所有依赖的库文件。文件较大但更方便分发。-c:生成一个控制台应用程序,可在命令行中运行。-w:生成一个窗口应用程序,不显示控制台窗口。-i <图标文件>:指定生成的可执行文件的图标。-n <程序名>:指定生成的可执行文件的文件名。-p <路径>:添加额外的模块搜索路径。-r <资源文件>:将指定的文件或目录添加为资源文件,可在程序运行时访问。--add-data <源路径>:<目标路径>:将源路径下的文件或目录添加为资源文件,可在程序运行时访问。--hidden-import <模块名>:手动指定需要导入的模块(PyInstaller 未自动检测到时使用)。--clean:打包前清理之前生成的临时文件。(即仅生成exe)--onefile:与-F相同,生成单个可执行文件。--console:与-c相同,生成控制台应用程序。--windowed:与-w相同,生成窗口应用程序。
——来自GPT老师
打包后 pathlib.Path(__file__) 无法正确获取路径的原因与解决方案
当你使用 PyInstaller 的 --onefile(-F) 模式打包程序时,
PyInstaller 会在运行时自动将所有文件 临时解压 到一个随机生成的目录,例如:
C:\Users\<用户名>\AppData\Local\Temp\_MEI151002\
然后从这个临时目录中执行你的程序。
因此,执行以下代码时:
pathlib.Path(__file__)
返回的路径自然会是:
C:\Users\<用户名>\AppData\Local\Temp\_MEI151002\main.py
而不是你的项目原始目录。
✅ 正确的解决方案
要兼容 源码运行 与 打包运行 两种情况,应使用以下写法:
import sys
import pathlib
if getattr(sys, 'frozen', False):
# 如果是被打包的 exe 运行
app_path = pathlib.Path(sys.executable).parent
else:
# 如果是源码运行
app_path = pathlib.Path(__file__).parent
print("程序运行目录:", app_path)
说明:
sys.frozen是 PyInstaller 在运行时自动注入的标志。sys.executable指向当前可执行文件的完整路径。__file__仅在源码状态下可用。
🧱 示例修正版
import sys
import pathlib
class Functions:
def __init__(self):
self.key_path = r"Software\Microsoft\Windows\CurrentVersion\Run"
self.app_name = "DeviceUsageTime"
if getattr(sys, 'frozen', False):
# 打包后运行
self.app_path = pathlib.Path(sys.executable).parent
else:
# 源码运行
self.app_path = pathlib.Path(__file__).parent
print("当前程序路径:", self.app_path)
🧠 为什么 PyInstaller 这么做?
在 --onefile 模式下,PyInstaller 会:
- 将所有依赖文件压缩进一个 EXE。
- 启动时解压到
_MEIxxxxx临时文件夹。 - 从该文件夹运行虚拟环境。
- 程序退出后自动删除该文件夹。
因此,__file__ 永远会指向这个临时路径。
若要获取 真正的 EXE 所在目录(例如存放配置文件、日志、资源等),
请使用 sys.executable。
🧩 推荐封装:资源路径函数
可以定义一个通用函数,在源码和打包模式下都能正确找到文件路径:
def resource_path(relative_path):
"""获取资源文件的绝对路径,兼容打包和源码运行"""
import sys, pathlib
if getattr(sys, 'frozen', False):
base_path = pathlib.Path(sys.executable).parent
else:
base_path = pathlib.Path(__file__).parent
return base_path / relative_path
使用方式:
config_file = resource_path("config.json")
这样即使打包成 EXE,也能正确读取配置文件或资源文件。
winreg 访问和修改 Windows 注册表。
仅能在 Windows 上可用。
一、注册表根键(预定义句柄)
- HKEY_CLASSES_ROOT
- HKEY_CURRENT_USER
- HKEY_LOCAL_MACHINE
- HKEY_USERS
- HKEY_CURRENT_CONFIG
这些是注册表的“根目录”,在调用注册表操作时需作为第一个参数传入。
二、常用访问权限常量
- KEY_READ
- KEY_WRITE
- KEY_SET_VALUE
- KEY_ALL_ACCESS
- KEY_WOW64_64KEY
- KEY_WOW64_32KEY
用于控制访问权限和注册表视图(32/64 位)。
三、值类型常量
- REG_SZ:字符串
- REG_MULTI_SZ:字符串列表
- REG_EXPAND_SZ:可扩展字符串(可含环境变量)
- REG_DWORD:32 位整数
- REG_QWORD:64 位整数
- REG_BINARY:二进制数据
四、常用函数与示例
打开键
winreg.OpenKey(root, sub_key, reserved=0, access=winreg.KEY_READ)
功能:打开已存在的注册表键,返回一个句柄(handle),可用于后续读/写/枚举等操作。
参数说明:
- root:预定义根句柄(常量),例如
winreg.HKEY_CURRENT_USER、winreg.HKEY_LOCAL_MACHINE等。指定从哪个根开始查找子键。 - sub_key:字符串,如
r"Software\\Example"。相对于 root 的子键路径。若该子键不存在则会抛出FileNotFoundError/OSError - reserved:整数(历史遗留,通常传 0)
- access:整数(常量),例如 winreg.KEY_READ, winreg.KEY_SET_VALUE, winreg.KEY_ALL_ACCESS 等。
-
说明:请求的访问权限(决定你能对打开的键做哪些操作)。可以用按位或 | 组合多个标志,例如
winreg.KEY_READ | winreg.KEY_WOW64_64KEY。 -
常见组合:
-
winreg.KEY_READ:只读访问(查询值、枚举子项等)。
-
winreg.KEY_SET_VALUE:允许写入值(SetValueEx)。
-
加上
winreg.KEY_WOW64_64KEY或winreg.KEY_WOW64_32KEY可显式选择 64/32 位注册表视图(在 64-bit Windows 下区分 32/64 位进程视图)。
-
import winreg
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\\Example", 0, winreg.KEY_READ)
winreg.CloseKey(key)
创建键
winreg.CreateKey(root, sub_key)
创建(或打开)一个子键并返回该键的句柄。如果子键已存在,则打开它
- root:同上
- sub_key:字符串,要创建或打开的子键路径
返回值:新创建或已存在子键的句柄
异常:权限不足可能抛 PermissionError。
备注:有更灵活的 CreateKeyEx(root, sub_key, reserved=0, access=winreg.KEY_WRITE),可指定 access(权限)和保留参数。若需要控制 32/64 位视图或访问权限推荐用 CreateKeyEx。
key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, r"Software\\Example\\MyApp")
winreg.CloseKey(key)
winreg.CreateKeyEx(root, sub_key, reserved=0, access=winreg.KEY_WRITE)
- root:同上
- sub_key:同上
- reservd:一般为0
- access:同上
设置值
winreg.SetValueEx(key, value_name, reserved, value_type, value)
在已打开的键 key 下设置一个值(写入/更新)。
- key:句柄对象
- value_name:要写入的值的名称,需为字符串或
None - reserved:通常传0,保留参数
- value_type:常量(例如 winreg.REG_SZ, winreg.REG_DWORD 等)。必须与value一致
- value:要传入的值
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\\Example\\MyApp", 0, winreg.KEY_SET_VALUE)
winreg.SetValueEx(key, "InstallPath", 0, winreg.REG_SZ, r"C:\\Program Files\\MyApp")
winreg.CloseKey(key)
读取值
winreg.QueryValueEx(key, value_name)
读取指定键名的值及其类型
- key:同上
- value_name:同上
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\\Example\\MyApp", 0, winreg.KEY_READ)
value, val_type = winreg.QueryValueEx(key, "InstallPath")
winreg.CloseKey(key)
删除值
winreg.DeleteValue(key, value_name)
仅删除值,不删除键
- key:同上
- value_name:同上
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\\Example\\MyApp", 0, winreg.KEY_SET_VALUE)
winreg.DeleteValue(key, "InstallPath")
winreg.CloseKey(key)
删除键
winreg.DeleteKey(root, sub_key)
删除指定的子键(注意:只能删除没有子键的键;若子键非空会失败)
- root:同上
- sub_key:要删除的子键路径字符串(相对于 root)。
异常:
-
若子键不存在抛 FileNotFoundError / OSError。
-
若子键包含子项抛 OSError(或 PermissionError)。
-
若权限不足抛 PermissionError。
winreg.DeleteKey(winreg.HKEY_CURRENT_USER, r"Software\\Example\\MyApp")
关闭键
winreg.CloseKey(key)
- key:应为有效句柄对象。重复关闭或传入非句柄可能抛出错误。
枚举子键与值
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\\Example")
# 枚举子键
i = 0
while True:
try:
subkey = winreg.EnumKey(key, i)
print("subkey:", subkey)
i += 1
except OSError:
break
# 枚举值
i = 0
while True:
try:
name, value, val_type = winreg.EnumValue(key, i)
print(name, value, val_type)
i += 1
except OSError:
break
winreg.CloseKey(key)
连接远程注册表
reg = winreg.ConnectRegistry(r"\\\\REMOTE_PC", winreg.HKEY_LOCAL_MACHINE)
五、实用示例
检查键是否存在
def key_exists(root, subkey):
try:
h = winreg.OpenKey(root, subkey, 0, winreg.KEY_READ)
winreg.CloseKey(h)
return True
except FileNotFoundError:
return False
设置开机启动项
def add_startup(name, exe_path):
key_path = r"Software\Microsoft\Windows\CurrentVersion\Run"
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_SET_VALUE)
winreg.SetValueEx(key, name, 0, winreg.REG_SZ, f'"{exe_path}"')
winreg.CloseKey(key)
六、权限与 32/64 位问题
- 在 64 位 Windows 上,32 位程序会访问
WOW6432Node分支。 - 显式指定访问视图:
winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Software\\SomeKey", 0, winreg.KEY_READ | winreg.KEY_WOW64_64KEY) - 修改系统级(HKLM)键时通常需要管理员权限。
七、异常类型
- FileNotFoundError:键或值不存在
- PermissionError:权限不足
- OSError:其他底层错误
八、总结
| 功能 | 函数 |
|---|---|
| 打开键 | OpenKey |
| 创建键 | CreateKey / CreateKeyEx |
| 读取值 | QueryValueEx |
| 设置值 | SetValueEx |
| 删除值 | DeleteValue |
| 删除键 | DeleteKey / DeleteKeyEx |
| 枚举键/值 | EnumKey / EnumValue |
| 远程访问 | ConnectRegistry |
keyboard 控制监听、模拟键盘输入
keyboard是一个用于 监听键盘事件、模拟键盘输入、注册快捷键 的第三方库
一、安装与注意事项
pip install keyboard
⚠️ 注意
- Windows / Linux:基本可用
- macOS:需要 root 权限
- Linux:部分发行版需要 sudo
- 全局键盘监听可能被安全软件拦截
二、基础使用
1️⃣ 导入库
import keyboard
2️⃣ 判断按键是否被按下
keyboard.is_pressed('a')
keyboard.is_pressed('space')
keyboard.is_pressed('ctrl')
3️⃣ 等待按键(阻塞)
keyboard.wait('esc')
三、监听键盘事件
4️⃣ 读取单次事件
event = keyboard.read_event()
print(event.name, event.event_type)
5️⃣ 全局监听
keyboard.hook(lambda e: print(e.name, e.event_type))
keyboard.wait()
6️⃣ 仅监听按下 / 松开
keyboard.on_press(lambda e: print(e.name))
keyboard.on_release(lambda e: print(e.name))
四、快捷键(Hotkey)
7️⃣ 注册快捷键
keyboard.add_hotkey('ctrl+alt+a', lambda: print("触发"))
keyboard.wait()
8️⃣ 取消快捷键
keyboard.remove_all_hotkeys()
五、模拟键盘输入
9️⃣ 模拟按键
keyboard.send('ctrl+c')
🔟 输入文本
keyboard.write("Hello World", delay=0.1)
六、屏蔽与拦截
11️⃣ 屏蔽按键
keyboard.block_key('esc')
七、录制与回放
12️⃣ 录制
events = keyboard.record(until='esc')
13️⃣ 回放
keyboard.play(events)
八、常见按键名称
| 键 | 名称 |
|---|---|
| 空格 | space |
| 回车 | enter |
| ESC | esc |
| Ctrl | ctrl |
| Shift | shift |
| Alt | alt |
| 方向键 | up/down/left/right |
| Win | win |
九、注意事项
- 不适合服务器环境
- GUI 程序避免阻塞调用
NSIS 将Python程序打包成一个Windows可安装程序(与pyinstaller的可执行程序不同)
官网
先到下载页获取工具,然后再pip安装:pip install pynsist
logging 内置的日志模块
Python 内置了 logging 模块,用于记录程序运行信息、调试信息和错误信息等。下面整理了常见的使用方法。
1️⃣ 基本使用
最简单的方式是直接用 logging 的基础配置和日志函数:
import logging
logging.basicConfig(level=logging.INFO) # 设置日志等级
logging.debug("调试信息")
logging.info("普通信息")
logging.warning("警告信息")
logging.error("错误信息")
logging.critical("严重错误")
- 日志等级(由低到高):
DEBUG→INFO→WARNING→ERROR→CRITICAL basicConfig只会在第一次配置时生效。
2️⃣ 配置输出格式
可以自定义日志格式,包括时间、模块、行号等:
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
常用格式符号:
%(asctime)s→ 时间%(name)s→ logger 名称%(levelname)s→ 日志等级%(message)s→ 日志信息%(filename)s→ 文件名%(lineno)d→ 行号%(funcName)s→ 函数名
3️⃣ 输出到文件
不仅能在控制台打印,也能写入文件:
logging.basicConfig(
filename="app.log", # 输出到文件
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
logging.info("写入文件的日志")
- 可以使用
filemode="w"来覆盖写,默认是追加模式a。
4️⃣ 使用 Logger、Handler、Formatter(高级)
logging 的核心思想是 Logger → Handler → Formatter:
import logging
# 1. 创建日志记录器
logger = logging.getLogger("my_logger")
logger.setLevel(logging.DEBUG)
# 2. 创建处理器(控制台和文件)
console_handler = logging.StreamHandler()
file_handler = logging.FileHandler("app.log")
# 3. 创建格式器
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
# 4. 绑定格式器到处理器
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
# 5. 绑定处理器到 logger
logger.addHandler(console_handler)
logger.addHandler(file_handler)
# 6. 输出日志
logger.info("信息日志")
logger.error("错误日志")
特点:
- Logger:日志记录器,产生日志
- Handler:处理器,决定日志输出到哪里(控制台、文件、网络)
- Formatter:格式器,定义日志输出格式
5️⃣ 捕获异常日志
可以直接用 exc_info=True 记录异常堆栈:
try:
1 / 0
except ZeroDivisionError:
logging.error("发生异常", exc_info=True)
日志中会打印完整的 Traceback。
6️⃣ 日志等级过滤
- 可以在
basicConfig(level=...)或logger.setLevel()设置最低输出等级 - Handler 也可以单独设置等级
console_handler.setLevel(logging.WARNING) # 控制台只显示 WARNING 以上
file_handler.setLevel(logging.DEBUG) # 文件记录所有日志
7️⃣ 日志轮转(日志文件大小控制)
用 RotatingFileHandler 控制日志文件大小:
from logging.handlers import RotatingFileHandler
handler = RotatingFileHandler("app.log", maxBytes=1024*1024, backupCount=3)
logger.addHandler(handler)
maxBytes:日志文件最大字节backupCount:备份文件数量,超过自动覆盖
✅ 总结
- 快速记录:
logging.info() / warning() / error() - 自定义输出:
basicConfig(format=...) - 文件 + 控制台:Logger + Handler + Formatter
- 捕获异常:
exc_info=True - 日志轮转:
RotatingFileHandler或TimedRotatingFileHandler - 灵活等级控制:Logger、Handler 可单独设置
collections 用于补充和增强内置数据结构的模块
一、namedtuple —— 有名字的元组/最小类
作用
在保持元组“轻量、不可变”特性的同时,提升字段的可读性。
适合生成一个只有属性没有方法的最小类
特点
- 不可变
- 内存占用小
- 通过属性访问字段
示例1
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
p.x
p.y
示例2
>>> from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates') ➊
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667)) ➋
>>> tokyo
City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722,
139.691667))
>>> tokyo.population ➌
36.933
>>> tokyo.coordinates
(35.689722, 139.691667)
>>> tokyo[1]
'JP'
适用场景
- 数据记录结构(Card、Point、UserInfo)
- 配置对象
- 只读数据模型
属性和方法
_fields(属性)
_fields 属性是一个包含这个类所有字段名称的元组。
>>> City._fields ➊
('name', 'country', 'population', 'coordinates')
_make()与_asdict()
_make()通 过 接 受 一 个 可 迭 代 对 象 来 生 成 这 个 类 的 一 个 实 例, 它 的 作 用 跟City(*delhi_data)是一样的。_asdict()把具名元组以collections.OrderedDict的形式返回,我们可以利用它来把元组里的信息友好地呈现出来。
>>> LatLong = namedtuple('LatLong', 'lat long')
>>> delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
>>> delhi = City._make(delhi_data) ➋
>>> delhi._asdict() ➌
OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population',
21.935), ('coordinates', LatLong(lat=28.613889, long=77.208889))])
>>> for key, value in delhi._asdict().items():
print(key + ':', value)
name: Delhi NCR
country: IN
population: 21.935
coordinates: LatLong(lat=28.613889, long=77.208889)
二、deque —— 双端队列(高性能)
作用
在两端频繁插入和删除的场景下,替代 list。
核心优势
- 头尾操作时间复杂度 O(1)
- list 的
pop(0)是 O(n),性能差
示例
from collections import deque
dq = deque([1, 2, 3])
dq.append(4)
dq.appendleft(0)
dq.pop()
dq.popleft()
适用场景
- 队列 / 栈
- BFS / DFS
- 消息队列
- 滑动窗口
三、Counter —— 计数器(非常常用)
作用
用于统计元素出现的次数。
示例
from collections import Counter
c = Counter("abracadabra")
常用方法
c.most_common(3)
c['a']
适用场景
- 词频统计
- 日志分析
- 排行榜
- 数据分析预处理
四、defaultdict —— 带默认值的字典
作用
自动初始化默认值,避免大量 if 判断和 KeyError。
对比写法
普通 dict:
d = {}
if k not in d:
d[k] = []
d[k].append(v)
defaultdict:
from collections import defaultdict
d = defaultdict(list)
d[k].append(v)
常见默认工厂
defaultdict(list)
defaultdict(set)
defaultdict(int)
适用场景
- 数据分组
- 索引构建
- 统计累加
- 图结构表示
bisect 对有序列表利用二分进行查询与插入
下面给你一个最实用、最常见的 bisect 用法总结,你可以直接当“速查表”用。
1️⃣ 在有序列表中插入元素(保持有序)
✅ 插到最左边(相同元素前面)
bisect.insort_left(a, x)
✅ 插到最右边(相同元素后面)
bisect.insort_right(a, x)
# 或者 bisect.insort(a, x)
2️⃣ 查找元素应该插入的位置(不插入)
✅ 找左边插入点(相同元素前)
idx = bisect.bisect_left(a, x)
✅ 找右边插入点(相同元素后)
idx = bisect.bisect_right(a, x)
# 或者 bisect.bisect(a, x)
3️⃣ 判断元素是否存在(O(log n))
i = bisect.bisect_left(a, x)
exists = (i < len(a) and a[i] == x)
4️⃣ 统计有序列表中某个值的出现次数
count = bisect.bisect_right(a, x) - bisect.bisect_left(a, x)
5️⃣ 统计区间范围内元素个数
例如统计 a 中在 [low, high] 区间内的元素数量:
count = bisect.bisect_right(a, high) - bisect.bisect_left(a, low)
6️⃣ 用来做“分段/分级”映射(很常见)
比如成绩分级:
grades = [60, 70, 80, 90]
levels = ['不及格', '及格', '中', '良', '优']
score = 85
level = levels[bisect.bisect(grades, score)]
print(level) # 良
dotenv将配置文件临时载入环境变量
示例
from dotenv import load_dotenv
import os
load_dotenv("D:\Code\PythonCode\LangChain\environment.env")
deepseek_api_key = os.getenv("DeepSeek_API_KEY")
deepseek_base_url = os.getenv("DeepSeek_BASE_URL")

浙公网安备 33010602011771号