如何避免PyQt按钮clicked信号在装饰器下传递布尔值?
问题描述
我正在使用Qt Designer和PyQt5开发QT项目,其中一个按钮的clicked信号会传递布尔值。绑定信号与函数的代码如下(装饰器位于类内部,且无论使用何种装饰器,clicked信号都会传入布尔参数):
class Demo: def __init__(self): # bind the signal and function ... self.ui.pushButton_disconnect.clicked.connect( self.robot.disconnect_devices ) ... def my_decorator(func): def wrapper(self,*args,**kwargs): ''' args and kwargs is necessary because other decorated functions have parameters ''' # do something return func(self,*args,**kwargs) return wrapper # function @my_decorator def disconnect_devices(self, *args): print(args) # do something
目前我必须使用*args来接收传入的False,我知道可以在connect中使用lambda来规避此问题。我发现原因是装饰器中使用了*args,导致clicked信号自动传入参数,因此函数必须用*args接收。请问有没有其他解决方法?或者能否将clicked信号设置为无参数信号?
解决方案
方法1:让装饰器自动适配函数参数
利用inspect模块获取目标函数的签名,只传递它能接收的参数,既保留装饰器对带参函数的兼容性,又能让无参函数自动忽略多余参数:
import inspect class Demo: def __init__(self): # ... 原有初始化代码 ... def my_decorator(func): def wrapper(self, *args, **kwargs): # 获取函数签名,排除第一个self参数 sig = inspect.signature(func) param_names = list(sig.parameters.keys())[1:] # 筛选出函数能接收的位置参数和关键字参数 valid_args = args[:len(param_names)] valid_kwargs = {k: v for k, v in kwargs.items() if k in param_names} # 执行装饰逻辑 # do something return func(self, *valid_args, **valid_kwargs) return wrapper @my_decorator def disconnect_devices(self): # 无需*args,直接定义无参函数 # 执行设备断开逻辑 pass
方法2:显式使用无参数的clicked信号重载
QPushButton的clicked信号有两个重载版本,指定使用无参数的那个版本,信号触发时就不会传递布尔值:
# 连接信号时指定无参数重载 self.ui.pushButton_disconnect.clicked[()].connect( self.robot.disconnect_devices )
之后disconnect_devices就能直接定义为无参数函数,装饰器的*args不会收到多余参数。
方法3:在装饰器中针对性忽略布尔参数
如果只需要处理clicked信号的布尔参数,可以在装饰器里判断并忽略这类参数,适合特定场景的快速优化:
class Demo: def my_decorator(func): def wrapper(self, *args, **kwargs): # 检查是否是单个布尔参数(clicked信号默认传入的类型) if len(args) == 1 and isinstance(args[0], bool): # 忽略该参数,直接调用原函数 return func(self) # 其他情况正常传递参数 return func(self, *args, **kwargs) return wrapper @my_decorator def disconnect_devices(self): # 执行设备断开逻辑 pass
内容的提问来源于stack exchange,提问作者肉蛋充肌
相关产品推荐
相关产品推荐

