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)
      

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.txt
      

      filename为基本位置参数名,可自定义。
      调用时通过调用args.基本位置参数名来实现

      1. 基本位置参数对定义顺序敏感,会严格按照定义顺序来解析
      2. 直接写值,无前缀
      3. 该参数定义后必须提供
      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
      

      短参数一般由-加上一个字母组成,长参数一般由--加上一个单词组成


      1. 短参数与长参数的参数名可以自定义
      2. 短参数是可选的,长参数是必须的。在调用参数时只能调用长参数而无法调用短参数
      3. 可以通过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
      

      1. action类型若选为该类型则不能传值
      2. 在选择该选项时,值为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.0
      
      3.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_INPUT
      
      11.必需参数 (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

多线程

常用方法

  1. 创建线程
def server():
    pass

mqtt_thread = threading.Thread(target=server)#把整个示例作为封装成一个函数传递给线程
mqtt_thread.start()#启动线程
  1. 结束线程:使用 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.")
  1. 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() 通知线程停止。
  • 比全局变量更安全,适用于更复杂的多线程场景。

注:多个线程之间共用全局变量资源

  1. 主线程退出时结束子线程
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()      # 释放锁

注意

  1. 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
  1. 采用多线程时,一条线程为更新字典的函数,一条线程为把字典保存为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:直接输出原始字符(方便阅读中文)。
  • 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秒

三种时间格式

  1. 时间戳(timestamp)
  2. 时间元组(struct_time)
  3. 时间字符串(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")

常用方法

  1. 基本属性
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的~

  1. 路径拼接(/ 操作符被重载,用来拼接路径:)
base = Path("/var/www")
file = base / "media" / "icon.png"
print(file)   # /var/www/media/icon.png
  1. 路径判断
p.exists()      # 是否存在
p.is_file()     # 是否为文件
p.is_dir()      # 是否为目录
p.is_absolute() # 是否为绝对路径
  1. 路径解析与规范化
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):
    # 拒绝
  1. 路径组合与分解
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
  1. 文件操作(直接读写)
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())
  1. 遍历目录
p = Path("/var/www/media")

for child in p.iterdir():       # 只遍历一层
    print(child)

for file in p.rglob("*.png"):   # 递归遍历所有 .png 文件
    print(file)
  1. 创建、删除路径
p = Path("data/new_folder")
p.mkdir(parents=True, exist_ok=True)  # 创建目录 
    #parents=True:如果父目录不存在则一并创建。
    #exist_ok=True:如果目录存在不会报错
p.rmdir()                             # 删除空目录
  1. 路径比较与关系判断(防目录穿越)
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("不在子目录内")
  1. 常用技巧
目的 示例
获取当前工作目录 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 会:

  1. 将所有依赖文件压缩进一个 EXE。
  2. 启动时解压到 _MEIxxxxx 临时文件夹。
  3. 从该文件夹运行虚拟环境。
  4. 程序退出后自动删除该文件夹。

因此,__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_USERwinreg.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_64KEYwinreg.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("严重错误")
  • 日志等级(由低到高):DEBUGINFOWARNINGERRORCRITICAL
  • 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
  • 日志轮转RotatingFileHandlerTimedRotatingFileHandler
  • 灵活等级控制: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")
posted @ 2026-07-02 18:09  畅畅c  阅读(2)  评论(0)    收藏  举报