第8.24节 使用__subclasses__查看类的直接子类

博客介绍了Python类中__subclasses__()方法,它与__bases__相对应,用于查看类的直接子类集合。调用方式为类名.__subclasses__(),会返回所有子类的列表,还给出了查看object基类直接子类的案例,也建议用自定义父类验证。

《第8.9节 Python类中内置的__bases__属性》中介绍了__bases__这个类的特殊变量可以查看类的直接父类,而__subclasses__() 方法的使用则与__bases__相对应,是查看类的直接子类集合。

调用方式:类名. subclasses()
返回所有子类的列表

案例:object.__subclasses__()
可以输出所有object基类的直接子类。
本节简单介绍了__ subclasses __方法,内容非常简单,除了老猿举例的object类查看,大家也可以用自定义父类查看验证。
老猿Python,跟老猿学Python!
博客地址:https://blog.youkuaiyun.com/LaoYuanPython

请大家多多支持,点赞、评论和加关注!谢谢!

import tkinter as tk from tkinter import ttk import time import sys import os import platform import ctypes import csv import threading import numpy as np import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from ctypes import windll, wintypes from collections import defaultdict from datetime import datetime # 解决中文警告问题 import matplotlib as mpl mpl.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei'] # 指定默认字体 mpl.rcParams['axes.unicode_minus'] = False # 解决负号显示问题 class HighPrecisionTimer: """高精度计时器基""" def __init__(self): self.start_time = 0 self.total_elapsed = 0 self.running = False self.interrupt_count = 0 # 中断计数器 self.records = [] # 记录每次计时结果 def start(self): """开始计时""" if not self.running: self.start_time = self.current_time() self.running = True def stop(self): """停止计时""" if self.running: elapsed = self.current_time() - self.start_time self.total_elapsed += elapsed self.running = False def reset(self): """重置计时器""" self.total_elapsed = 0 self.running = False self.interrupt_count = 0 self.records = [] def current_elapsed(self): """获取当前已过时间(毫秒)""" if self.running: return self.total_elapsed + (self.current_time() - self.start_time) return self.total_elapsed def current_time(self): """抽象方法,由子类实现具体计时方案""" raise NotImplementedError("Subclasses must implement current_time()") def record_current(self): """记录当前计时值""" if self.running: elapsed = self.current_elapsed() self.records.append({ "timestamp": datetime.now(), "elapsed": elapsed, "label": f"记录 {len(self.records)+1}" }) return elapsed return 0 def get_cpu_utilization(self, physical_time): if physical_time > 0: return min(100, max(0, (self.current_elapsed() / physical_time) * 100)) return 0 def record_interrupt(self): """记录中断事件""" self.interrupt_count += 1 class PerformanceCounterTimer(HighPrecisionTimer): """基于性能计数器的物理计时方案""" def __init__(self): super().__init__() # 获取性能计数器频率 if platform.system() == 'Windows': self.frequency = ctypes.c_int64() windll.kernel32.QueryPerformanceFrequency(ctypes.byref(self.frequency)) self.frequency = self.frequency.value else: # Linux/macOS使用time.perf_counter self.frequency = 1e9 # 1秒 = 1e9纳秒 def current_time(self): """获取当前性能计数器时间(毫秒)""" if platform.system() == 'Windows': counter = ctypes.c_int64() windll.kernel32.QueryPerformanceCounter(ctypes.byref(counter)) return (counter.value * 1000) / self.frequency # 转换为毫秒 else: # 跨平台方案 return time.perf_counter() * 1000 class CPUCycleTimer(HighPrecisionTimer): """基于CPU周期的计时方案""" def __init__(self): super().__init__() # 获取CPU频率 self.frequency = self.get_cpu_frequency() self.power_model = self.create_power_model() # 创建功耗模型 def get_cpu_frequency(self): """尝试获取CPU频率""" try: if platform.system() == 'Windows': # Windows获取CPU频率 import winreg key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"HARDWARE\DESCRIPTION\System\CentralProcessor\0") value, _ = winreg.QueryValueEx(key, "~MHz") winreg.CloseKey(key) return value * 1e6 # MHz转换为Hz else: # Linux/macOS获取CPU频率 with open('/proc/cpuinfo') as f: for line in f: if 'cpu MHz' in line: return float(line.split(':')[1].strip()) * 1e6 # 默认值 return 3.5e9 # 3.5 GHz except: return 3.5e9 # 3.5 GHz def current_time(self): """获取当前CPU周期计数并转换为毫秒""" if platform.system() == 'Windows': return time.perf_counter_ns() / 1_000_000 # 返回毫秒级精确时间 else: # 在实际应用中应使用RDTSC指令 return time.process_time() * 1000 def create_power_model(self): # 简化的线性模型: P = a * utilization + b return lambda u: 15 + 85 * (u/100) # 基础功耗15W + 动态功耗 def estimate_energy(self, physical_time): utilization = self.get_cpu_utilization(physical_time) power = self.power_model(utilization) # 当前功耗(W) time_seconds = physical_time / 1000 # 转换为秒 return power * time_seconds # 能耗(J) class TimerApp: """计时器应用GUI""" def __init__(self, root): self.root = root root.title("高精度计时器 - 专业版") root.geometry("900x700") root.resizable(True, True) # 创建两种计时器实例 self.performance_timer = PerformanceCounterTimer() self.cpu_cycle_timer = CPUCycleTimer() # 当前选中的计时方案 self.current_timer = self.performance_timer self.interrupt_monitor_running = False # 计时记录列表 self.time_records = [] # 创建UI self.create_widgets() # 性能优化计数器 self.update_count = 0 # 启动UI更新循环 self.update_display() # 启动中断监控线程 self.start_interrupt_monitor() def create_widgets(self): """创建界面组件""" # 主框架 main_frame = tk.Frame(self.root) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 左侧控制面板 control_frame = tk.Frame(main_frame) control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5) # 方案选择 mode_frame = tk.LabelFrame(control_frame, text="计时方案", padx=10, pady=10) mode_frame.pack(fill=tk.X, pady=5) self.mode_var = tk.StringVar(value="performance") modes = [("性能计数器 (物理时间)", "performance"), ("CPU周期 (CPU时间)", "cpu")] for text, mode in modes: rb = tk.Radiobutton(mode_frame, text=text, variable=self.mode_var, value=mode, command=self.switch_mode) rb.pack(anchor=tk.W, padx=5, pady=2) # 控制按钮 btn_frame = tk.Frame(control_frame) btn_frame.pack(fill=tk.X, pady=10) self.start_btn = tk.Button(btn_frame, text="开始", width=12, command=self.start_stop) self.start_btn.pack(side=tk.LEFT, padx=5) reset_btn = tk.Button(btn_frame, text="重置", width=12, command=self.reset) reset_btn.pack(side=tk.LEFT, padx=5) # 记录按钮 self.record_btn = tk.Button(btn_frame, text="记录本次", width=12, command=self.record_current, state=tk.DISABLED) self.record_btn.pack(side=tk.LEFT, padx=5) # 统计按钮 stats_btn = tk.Button(btn_frame, text="生成报告", width=12, command=self.generate_report) stats_btn.pack(side=tk.LEFT, padx=5) # CPU信息 info_frame = tk.LabelFrame(control_frame, text="系统信息", padx=10, pady=10) info_frame.pack(fill=tk.X, pady=5) cpu_freq = self.cpu_cycle_timer.frequency freq_text = f"CPU频率: {cpu_freq/1e9:.2f} GHz" if cpu_freq >= 1e9 else f"CPU频率: {cpu_freq/1e6:.0f} MHz" self.cpu_label = tk.Label(info_frame, text=freq_text, justify=tk.LEFT) self.cpu_label.pack(anchor=tk.W) cores_text = f"CPU核心数: {os.cpu_count()}" tk.Label(info_frame, text=cores_text, justify=tk.LEFT).pack(anchor=tk.W) # 中断统计 interrupt_frame = tk.LabelFrame(control_frame, text="中断统计", padx=10, pady=10) interrupt_frame.pack(fill=tk.X, pady=5) self.interrupt_label = tk.Label(interrupt_frame, text="中断次数: 0") self.interrupt_label.pack(anchor=tk.W) # 右侧数据显示 display_frame = tk.Frame(main_frame) display_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5) # 双模式时间显示 time_frame = tk.LabelFrame(display_frame, text="时间显示", padx=10, pady=10) time_frame.pack(fill=tk.X, pady=5) # 物理时间显示 - 添加颜色(蓝色) physical_frame = tk.Frame(time_frame) physical_frame.pack(fill=tk.X, pady=5) tk.Label(physical_frame, text="物理时间:", width=10).pack(side=tk.LEFT) self.physical_label = tk.Label(physical_frame, text="00:00:00.000", font=("Consolas", 12), fg="blue") self.physical_label.pack(side=tk.LEFT) # CPU时间显示 - 添加颜色(红色) cpu_frame = tk.Frame(time_frame) cpu_frame.pack(fill=tk.X, pady=5) tk.Label(cpu_frame, text="CPU时间:", width=10).pack(side=tk.LEFT) self.cpu_time_label = tk.Label(cpu_frame, text="00:00:00.000", font=("Consolas", 12), fg="red") self.cpu_time_label.pack(side=tk.LEFT) # 计时记录框架 records_frame = tk.LabelFrame(display_frame, text="计时记录", padx=10, pady=10) records_frame.pack(fill=tk.X, pady=5) # 创建记录表格 columns = ("序号", "标签", "物理时间", "CPU时间", "差值") self.records_tree = ttk.Treeview(records_frame, columns=columns, show="headings", height=5) # 设置列标题 for col in columns: self.records_tree.heading(col, text=col) self.records_tree.column(col, width=80, anchor=tk.CENTER) # 设置列宽 self.records_tree.column("标签", width=120) # 添加滚动条 scrollbar = ttk.Scrollbar(records_frame, orient="vertical", command=self.records_tree.yview) self.records_tree.configure(yscrollcommand=scrollbar.set) self.records_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 统计图表 chart_frame = tk.LabelFrame(display_frame, text="计时统计图", padx=10, pady=10) chart_frame.pack(fill=tk.BOTH, expand=True, pady=5) # 创建图表 self.figure, self.ax = plt.subplots(figsize=(8, 4)) self.canvas = FigureCanvasTkAgg(self.figure, chart_frame) self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True) # 初始化图表 self.update_chart() def switch_mode(self): """切换计时方案""" selected = self.mode_var.get() if selected == "performance": self.current_timer = self.performance_timer else: self.current_timer = self.cpu_cycle_timer # 更新CPU频率显示 cpu_freq = self.cpu_cycle_timer.frequency freq_text = f"CPU频率: {cpu_freq/1e9:.2f} GHz" if cpu_freq >= 1e9 else f"CPU频率: {cpu_freq/1e6:.0f} MHz" self.cpu_label.config(text=freq_text) def start_stop(self): """开始/停止计时 - 只操作当前选中的计时器""" if self.current_timer.running: self.current_timer.stop() self.start_btn.config(text="开始") self.record_btn.config(state=tk.DISABLED) else: # 只启动当前选中的计时器 self.current_timer.start() self.start_btn.config(text="停止") self.record_btn.config(state=tk.NORMAL) def record_current(self): """记录当前计时值""" if self.current_timer.running: # 获取当前两种计时器的值 physical_ms = self.performance_timer.current_elapsed() cpu_ms = self.cpu_cycle_timer.current_elapsed() # 创建记录 record = { "id": len(self.time_records) + 1, "label": f"记录 {len(self.time_records) + 1}", "physical": physical_ms, "cpu": cpu_ms, "difference": abs(physical_ms - cpu_ms) } # 添加到记录列表 self.time_records.append(record) # 更新表格 self.update_records_table() # 更新图表 self.update_chart() def update_records_table(self): """更新计时记录表格""" # 清空现有数据 for item in self.records_tree.get_children(): self.records_tree.delete(item) # 添加新记录 for record in self.time_records: self.records_tree.insert("", "end", values=( record["id"], record["label"], f"{record['physical']:.1f} ms", f"{record['cpu']:.1f} ms", f"{record['difference']:.1f} ms" )) def update_chart(self): """更新计时统计图表""" self.ax.clear() if self.time_records: # 准备数据 labels = [r["label"] for r in self.time_records] physical_times = [r["physical"] for r in self.time_records] cpu_times = [r["cpu"] for r in self.time_records] x = np.arange(len(labels)) width = 0.35 # 绘制柱状图 rects1 = self.ax.bar(x - width/2, physical_times, width, label='物理时间', color='blue') rects2 = self.ax.bar(x + width/2, cpu_times, width, label='CPU时间', color='red') # 添加标签、标题等 self.ax.set_ylabel('时间 (ms)') self.ax.set_title('计时记录对比') self.ax.set_xticks(x) self.ax.set_xticklabels(labels) self.ax.legend() # 添加数值标签 self.ax.bar_label(rects1, padding=3, fmt='%.1f') self.ax.bar_label(rects2, padding=3, fmt='%.1f') # 调整布局 self.figure.tight_layout() else: # 没有记录时显示提示信息 self.ax.text(0.5, 0.5, '暂无计时记录', horizontalalignment='center', verticalalignment='center', transform=self.ax.transAxes, fontsize=14) self.canvas.draw() def reset(self): """重置当前计时器""" self.current_timer.reset() self.start_btn.config(text="开始") self.record_btn.config(state=tk.DISABLED) # 更新显示 self.update_display() def start_interrupt_monitor(self): """启动中断监控线程""" if not self.interrupt_monitor_running: self.interrupt_monitor_running = True threading.Thread(target=self.monitor_interrupts, daemon=True).start() def monitor_interrupts(self): """模拟中断监控""" while self.interrupt_monitor_running: time.sleep(0.1) # 在实际应用中,这里应读取系统中断计数器 if self.current_timer.running: # 模拟随机中断 if np.random.random() < 0.02: # 2%概率发生中断 self.performance_timer.record_interrupt() self.cpu_cycle_timer.record_interrupt() self.root.after(0, self.update_interrupt_count) def update_interrupt_count(self): """更新中断计数显示""" count = self.performance_timer.interrupt_count self.interrupt_label.config(text=f"中断次数: {count}") def generate_report(self): """生成详细分析报告并保存为CSV文件""" filename = f"timer_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" with open(filename, 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) # 写入报告头部信息 writer.writerow(["高精度计时器分析报告"]) writer.writerow(["生成时间", datetime.now().strftime("%Y-%m-%d %H:%M:%S")]) writer.writerow([]) # 写入系统信息 writer.writerow(["系统信息"]) writer.writerow(["操作系统", platform.platform()]) writer.writerow(["CPU核心数", os.cpu_count()]) cpu_freq = self.cpu_cycle_timer.frequency freq_text = f"{cpu_freq/1e9:.2f} GHz" if cpu_freq >= 1e9 else f"{cpu_freq/1e6:.0f} MHz" writer.writerow(["CPU频率", freq_text]) writer.writerow(["Python版本", sys.version]) writer.writerow([]) # 格式化时间函数 def format_ms(ms): hours, rem = divmod(ms, 3600000) minutes, rem = divmod(rem, 60000) seconds, milliseconds = divmod(rem, 1000) return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}.{int(milliseconds):03d}" # 写入时间指标 physical_time = self.performance_timer.total_elapsed cpu_time = self.cpu_cycle_timer.total_elapsed wait_time = max(0, physical_time - cpu_time) # 系统等待时间 writer.writerow(["时间指标"]) writer.writerow(["度量项", "数值(毫秒)", "格式化时间"]) writer.writerow(["物理时间", f"{physical_time:.3f}", format_ms(physical_time)]) writer.writerow(["CPU时间", f"{cpu_time:.3f}", format_ms(cpu_time)]) writer.writerow(["系统等待时间", f"{wait_time:.3f}", format_ms(wait_time)]) writer.writerow([]) # 写入性能指标 utilization = self.cpu_cycle_timer.get_cpu_utilization(physical_time) if physical_time > 0 else 0 energy = self.cpu_cycle_timer.estimate_energy(physical_time) if physical_time > 0 else 0 writer.writerow(["性能指标"]) writer.writerow(["CPU利用率", f"{utilization:.2f}%"]) writer.writerow(["系统中断次数", self.performance_timer.interrupt_count]) writer.writerow(["估算能耗", f"{energy:.2f} J"]) writer.writerow([]) # 写入计时记录 writer.writerow(["计时记录"]) writer.writerow(["序号", "标签", "物理时间(ms)", "CPU时间(ms)", "差值(ms)"]) for i, record in enumerate(self.time_records, 1): writer.writerow([ i, record["label"], f"{record['physical']:.3f}", f"{record['cpu']:.3f}", f"{abs(record['physical'] - record['cpu']):.3f}" ]) writer.writerow([]) # 添加数学公式注解 writer.writerow(["计算公式注解"]) writer.writerow(["CPU利用率", r"$\eta = \frac{T_{cpu}}{T_{physical}} \times 100\%$"]) writer.writerow(["系统等待时间", r"$\Delta t = T_{physical} - T_{cpu}$"]) writer.writerow(["能耗估算", r"$E = \int_{0}^{T} P(u(t)) \, dt$", "(P=功耗模型)"]) # 显示成功消息 tk.messagebox.showinfo("报告生成", f"分析报告已保存至:\n{os.path.abspath(filename)}") def update_display(self): """更新UI显示""" # 获取两个计时器的当前时间 physical_ms = self.performance_timer.current_elapsed() cpu_ms = self.cpu_cycle_timer.current_elapsed() # 格式化时间 physical_str = self.ms_to_time_str(physical_ms) cpu_str = self.ms_to_time_str(cpu_ms) # 始终更新两个时间显示 self.physical_label.config(text=physical_str) self.cpu_time_label.config(text=cpu_str) # 计算性能指标 if physical_ms > 0: utilization = min(100, max(0, (cpu_ms / physical_ms) * 100)) wait_time = max(0, physical_ms - cpu_ms) energy = self.cpu_cycle_timer.estimate_energy(physical_ms) else: utilization = 0 wait_time = 0 energy = 0 # 更新性能指标显示 self.util_label.config(text=f"{utilization:.1f}%") self.wait_label.config(text=f"{wait_time:.1f} ms") self.energy_label.config(text=f"{energy:.1f} J") # 每100毫秒更新一次显示 self.root.after(100, self.update_display) def ms_to_time_str(self, ms): """将毫秒数格式化为 HH:MM:SS.ms 字符串""" ms = max(0, ms) # 确保非负 seconds, milliseconds = divmod(ms, 1000) minutes, seconds = divmod(seconds, 60) hours, minutes = divmod(minutes, 60) return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}.{int(milliseconds):03d}" if ms > 0 else "00:00:00.000" def __del__(self): """清理资源""" self.interrupt_monitor_running = False if __name__ == "__main__": root = tk.Tk() app = TimerApp(root) try: root.mainloop() finally: # 确保线程安全退出 app.interrupt_monitor_running = False [Running] python -u "e:\system\Desktop\项目所需文件\工具\计时器工具\timer copy 2.py" Traceback (most recent call last): File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy 2.py", line 567, in <module> app = TimerApp(root) ^^^^^^^^^^^^^^ File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy 2.py", line 182, in __init__ self.update_display() File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy 2.py", line 546, in update_display self.util_label.config(text=f"{utilization:.1f}%") ^^^^^^^^^^^^^^^ AttributeError: 'TimerApp' object has no attribute 'util_label'
最新发布
10-14
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LaoYuanPython

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值