子类实例化及线程调用方法报错求助(Modbus/AttributeError)
问题分析与解决方案
错误原因拆解
AttributeError: 'ModbusTcpClient' object has no attribute 'modbus'
你直接调用Temperature_Controll2.temp_controll这个未绑定的类方法作为线程目标,还把ModbusClient实例当成第一个参数传入。但实例方法的第一个参数self必须是Temperature_Controll2的实例,这里self被错误赋值为ModbusClient对象,它自然没有modbus属性。AttributeError: 'str' object has no attribute 'database_reading'
本质还是self参数传错了:线程参数args=(client, 'get')会让temp_controll的self接收client、value接收'get'。当调用self.database_reading()时,要么client没有这个方法,要么参数顺序错误导致self变成了字符串'get'——核心问题都是没有正确传入类实例作为self。
另外代码还有几个隐性问题:
Temperature_Controll2的__init__中,super调用的类名拼写错误(写成了Temperature_Controll)Echo的database_reading方法定义缺少冒号- 创建
t1线程时,target=server.serveforever()是直接执行方法而非传入方法对象,会导致主线程阻塞 Temperature_Controll2继承自Echo,但Echo的__init__需要4个参数,你只传了client,会触发参数不匹配错误
修正后的代码
import threading import time import logging from pymodbus.client import ModbusClient from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket from functools import partial # 假设HOST、PORT、PORTNUM已定义 HOST = "127.0.0.1" PORT = 502 PORTNUM = 8000 class Echo(WebSocket): def __init__(self, client, server, sock, address): super().__init__(server, sock, address) self.modbus = client def database_reading(self): # 补充缺失的冒号 # 替换为你的实际业务逻辑 data = "sample_sensor_data" print(f"读取数据库数据: {data}") return data class Temperature_Controll2(Echo): def __init__(self, client): # 由于Echo是WebSocket子类,需要传入父类要求的参数,这里用None作为占位 super().__init__(client, server=None, sock=None, address=None) # 父类已经初始化了self.modbus,这里可以省略重复赋值 def temp_controll(self, value): while True: print("=== 温度控制循环运行中 ===") try: rp = self.modbus.read_coils(524, 0x1) print(f"读取线圈状态: {rp.bits[0]}") except Exception as e: print(f"Modbus读取失败: {str(e)}") self.database_reading() time.sleep(1) # 添加休眠,避免CPU占用过高 def main(): logging.basicConfig(level=logging.INFO) with ModbusClient(host=HOST, port=PORT) as client: if not client.connect(): print("Modbus连接失败") return time.sleep(0.01) print(f"WebSocket服务器运行在端口 {PORTNUM}") server = SimpleWebSocketServer('', PORTNUM, partial(Echo, client)) # 正确步骤:先创建子类实例,再传入绑定好实例的方法 control_instance = Temperature_Controll2(client) t2 = threading.Thread(target=control_instance.temp_controll, args=('get',)) t2.daemon = True # 设置为守护线程,主程序退出时自动终止 t2.start() try: # 注意:target传入方法对象,不要加括号,否则会直接在主线程执行 t1 = threading.Thread(target=server.serveforever) t1.start() t1.join() # 等待WebSocket线程结束 finally: server.close() print("服务器已关闭") if __name__ == "__main__": main()
关键修正说明
- 正确实例化子类:先创建
Temperature_Controll2的实例,再将绑定了实例的temp_controll方法作为线程目标,这样self会自动指向类实例,无需手动传入。 - 修正父类调用:
super().__init__传入父类要求的所有参数(用None作为占位,因为单独运行控制逻辑不需要WebSocket的连接资源)。 - 线程目标修正:
server.serveforever不要加括号,否则会直接在主线程执行,导致程序阻塞。 - 添加异常处理与休眠:捕获Modbus读取错误避免循环崩溃,添加休眠降低CPU占用。
内容的提问来源于stack exchange,提问作者Gool
相关产品推荐
相关产品推荐

