pyside6-reviewer
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePySide6 Code Reviewer
PySide6代码审查专家
Expert code review for modern PySide6/Qt 6.8+ applications.
针对现代PySide6/Qt 6.8+应用的专业代码审查服务。
Review Process
审查流程
- Identify Qt version assumptions — Verify code targets Qt 6.8+ (no Qt5 compat)
- Check thread safety — All GUI operations on main thread, proper worker patterns
- Validate signal/slot usage — Modern connection syntax, proper signatures
- Assess Model/View implementation — Role usage, data method patterns, index validity
- Review resource management — Parent-child ownership, prevent leaks
- Evaluate async patterns — QThread, QtConcurrent, asyncio integration
- Check QML integration — Property bindings, type registration, context exposure
- 确认Qt版本适配 — 验证代码目标为Qt 6.8+(无Qt5兼容代码)
- 检查线程安全 — 所有GUI操作在主线程执行,采用正确的工作线程模式
- 验证信号/槽使用 — 现代连接语法,正确的签名匹配
- 评估Model/View实现 — 角色使用、数据方法模式、索引有效性
- 审查资源管理 — 父子对象所有权,防止内存泄漏
- 评估异步模式 — QThread、QtConcurrent、asyncio集成
- 检查QML集成 — 属性绑定、类型注册、上下文暴露
Critical Anti-Patterns (Always Flag)
严重反模式(必须标记)
python
undefinedpython
undefinedWRONG: GUI operation from worker thread
WRONG: GUI operation from worker thread
class Worker(QThread):
def run(self):
self.label.setText("Done") # CRASH: Cross-thread GUI access
class Worker(QThread):
def run(self):
self.label.setText("Done") # CRASH: Cross-thread GUI access
WRONG: Blocking the event loop
WRONG: Blocking the event loop
def on_button_click(self):
time.sleep(5) # FREEZES UI
requests.get(url) # FREEZES UI
def on_button_click(self):
time.sleep(5) # FREEZES UI
requests.get(url) # FREEZES UI
WRONG: Old-style signal connection (Qt4/5 legacy)
WRONG: Old-style signal connection (Qt4/5 legacy)
self.connect(button, SIGNAL("clicked()"), self.handler)
self.connect(button, SIGNAL("clicked()"), self.handler)
WRONG: String-based slot connection
WRONG: String-based slot connection
button.clicked.connect("self.handler") # Should be callable
button.clicked.connect("self.handler") # Should be callable
WRONG: No parent = memory leak risk
WRONG: No parent = memory leak risk
label = QLabel("text") # Should have parent or be assigned to layout
label = QLabel("text") # Should have parent or be assigned to layout
WRONG: Deleting QObject while signals pending
WRONG: Deleting QObject while signals pending
obj.deleteLater() # OK
del obj # WRONG if signals/slots active
obj.deleteLater() # OK
del obj # WRONG if signals/slots active
WRONG: Direct widget manipulation in QThread.run()
WRONG: Direct widget manipulation in QThread.run()
class BadWorker(QThread):
def run(self):
self.progress_bar.setValue(50) # Thread violation!
undefinedclass BadWorker(QThread):
def run(self):
self.progress_bar.setValue(50) # Thread violation!
undefinedModern Patterns (Require These)
现代编程模式(推荐使用)
Signal/Slot Connections
信号/槽连接
python
undefinedpython
undefinedQt 6 style - always use this
Qt 6 style - always use this
button.clicked.connect(self.on_click)
button.clicked.connect(lambda: self.handler(arg))
button.clicked.connect(self.on_click)
button.clicked.connect(lambda: self.handler(arg))
Typed signals with modern syntax
Typed signals with modern syntax
class Worker(QObject):
progress = Signal(int) # Single type
result = Signal(str, list) # Multiple types
error = Signal(Exception) # Exception passing
finished = Signal() # No arguments
undefinedclass Worker(QObject):
progress = Signal(int) # Single type
result = Signal(str, list) # Multiple types
error = Signal(Exception) # Exception passing
finished = Signal() # No arguments
undefinedThread-Safe Worker Pattern
线程安全的工作线程模式
python
class Worker(QObject):
finished = Signal()
progress = Signal(int)
result = Signal(object)
error = Signal(str)
@Slot()
def run(self):
try:
for i in range(100):
# Do work
self.progress.emit(i)
self.result.emit(data)
except Exception as e:
self.error.emit(str(e))
finally:
self.finished.emit()python
class Worker(QObject):
finished = Signal()
progress = Signal(int)
result = Signal(object)
error = Signal(str)
@Slot()
def run(self):
try:
for i in range(100):
# Do work
self.progress.emit(i)
self.result.emit(data)
except Exception as e:
self.error.emit(str(e))
finally:
self.finished.emit()Usage
Usage
thread = QThread()
worker = Worker()
worker.moveToThread(thread)
thread.started.connect(worker.run)
worker.finished.connect(thread.quit)
worker.finished.connect(worker.deleteLater)
thread.finished.connect(thread.deleteLater)
thread.start()
undefinedthread = QThread()
worker = Worker()
worker.moveToThread(thread)
thread.started.connect(worker.run)
worker.finished.connect(thread.quit)
worker.finished.connect(worker.deleteLater)
thread.finished.connect(thread.deleteLater)
thread.start()
undefinedAsync Integration (Qt 6.8+)
异步集成(Qt 6.8+)
python
import asyncio
from PySide6.QtAsyncio import QAsyncioEventLoopPolicypython
import asyncio
from PySide6.QtAsyncio import QAsyncioEventLoopPolicySet up asyncio with Qt event loop
Set up asyncio with Qt event loop
asyncio.set_event_loop_policy(QAsyncioEventLoopPolicy())
class AsyncWidget(QWidget):
async def fetch_data(self):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
def start_fetch(self):
asyncio.ensure_future(self.fetch_data())undefinedasyncio.set_event_loop_policy(QAsyncioEventLoopPolicy())
class AsyncWidget(QWidget):
async def fetch_data(self):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
def start_fetch(self):
asyncio.ensure_future(self.fetch_data())undefinedDetailed Reference Files
详细参考文档
- references/signals-slots.md — Signal/slot patterns, connection types, thread-safe emission
- references/model-view.md — QAbstractItemModel, roles, proxies, delegates
- references/threading.md — QThread, QtConcurrent, async patterns, thread pools
- references/widgets.md — Widget lifecycle, layouts, styling, high-DPI
- references/qml-integration.md — QML/Python bridge, properties, type registration
- references/performance.md — Paint optimization, model efficiency, lazy loading
- references/anti-patterns.md — Comprehensive anti-pattern catalog with fixes
- references/signals-slots.md — 信号/槽模式、连接类型、线程安全发射
- references/model-view.md — QAbstractItemModel、角色、代理、委托
- references/threading.md — QThread、QtConcurrent、异步模式、线程池
- references/widgets.md — 组件生命周期、布局、样式、高DPI适配
- references/qml-integration.md — QML/Python桥接、属性、类型注册
- references/performance.md — 绘制优化、模型效率、懒加载
- references/anti-patterns.md — 完整的反模式目录及修复方案
Review Checklist (Use for PRs)
PR审查检查清单(用于PR审查)
Thread Safety
线程安全
- All widget/GUI calls on main thread only
- Workers use signal/slot for UI updates
- No or blocking calls in main thread
time.sleep() - subclass only overrides
QThread, not constructor workrun() - used correctly (object has no parent)
moveToThread()
- 所有组件/GUI调用仅在主线程执行
- 工作线程通过信号/槽更新UI
- 主线程中无或阻塞调用
time.sleep() - 子类仅重写
QThread方法,不在构造函数中执行任务run() - 使用正确(对象无父级)
moveToThread()
Memory Management
内存管理
- Widgets have parents OR are added to layouts
- used for QObjects, never
deleteLater()del - Lambda connections don't capture stale references
- Circular signal connections avoided
- Model data returned by value, not reference
- 组件有父级 或 已添加到布局中
- QObjects使用,绝不使用
deleteLater()del - Lambda连接未捕获过期引用
- 避免循环信号连接
- 模型数据通过值返回,而非引用
Signal/Slot Correctness
信号/槽正确性
- Modern connection syntax (no strings)
- Signal signatures match slot signatures
- decorator on all slots
@Slot() - for cross-thread signals
Qt.QueuedConnection - Signals defined as class attributes
- 使用现代连接语法(无字符串)
- 信号签名与槽签名匹配
- 所有槽函数使用装饰器
@Slot() - 跨线程信号使用
Qt.QueuedConnection - 信号定义为类属性
Model/View
Model/View
- /
beginInsertRows()bracket changesendInsertRows() - emitted for updates
dataChanged - checked before access
index.isValid() - Custom roles use
Qt.UserRole + n - override for QML compatibility
roleNames()
- 数据变更使用/
beginInsertRows()包裹endInsertRows() - 更新时发射信号
dataChanged - 访问前检查
index.isValid() - 自定义角色使用
Qt.UserRole + n - 重写以兼容QML
roleNames()
Performance
性能
- No widget creation in paint events
- not
update()for redrawsrepaint() - Large lists use QAbstractItemModel (not QListWidget)
- Lazy loading for expensive data
- during batch updates
blockSignals()
- 绘制事件中不创建组件
- 重绘使用而非
update()repaint() - 大型列表使用QAbstractItemModel(而非QListWidget)
- 昂贵数据采用懒加载
- 批量更新时使用
blockSignals()
Qt 6.8+ Specifics
Qt 6.8+特性适配
- Using new enum scoping ()
Qt.AlignmentFlag.AlignCenter - for async patterns (not third-party)
QtAsyncio - macro equivalents for type registration
QML_ELEMENT - Property bindings via where appropriate
QProperty - New API for platform permissions
QPermission
- 使用新的枚举作用域(如)
Qt.AlignmentFlag.AlignCenter - 采用实现异步模式(而非第三方库)
QtAsyncio - 使用宏等效方式进行类型注册
QML_ELEMENT - 适当场景下通过实现属性绑定
QProperty - 使用新的API处理平台权限
QPermission