使用Snap7出现TypeError: NoneType对象不可调用问题排查求助
Snap7程序结束时触发TypeError: 'NoneType' object is not callable的根源分析与修复方案
问题情况
使用Snap7库读取PLC数据时,数据读取功能正常,但程序执行结束时会触发TypeError: 'NoneType' object is not callable错误。目前仅能通过设置snap7.client.Client.__del__ = lambda self: None跳过__del__方法临时解决,需找到问题根源及正式修复方案,以便将脚本集成到其他项目中。此前使用该库数月无异常,近期突然出现此问题。
相关代码
import snap7 plc = snap7.client.Client() plc.connect("20.0.0.20", 0, 1) data = plc.db_read(1, 0, 1) x = snap7.util.get_bool(data, 0, 0) print(x) data = plc.db_read(1, 0, 1) x = snap7.util.get_bool(data, 0, 1) print(x) data = plc.db_read(1, 0, 1) x = snap7.util.get_bool(data, 0, 2) print(x) data = plc.db_read(1, 0, 1) x = snap7.util.get_bool(data, 0, 3) print(x) plc.disconnect() plc.destroy() del plc
执行报错
True False True False Exception ignored in: <function Client.__del__ at 0x000001FD63E7EE80> Traceback (most recent call last): File "C:\Users\brunosilva\AppData\Local\Programs\Python\Python312\Lib\site-packages\snap7\client.py", line 74, in __del__ File "C:\Users\brunosilva\AppData\Local\Programs\Python\Python312\Lib\site-packages\snap7\client.py", line 92, in destroy File "C:\Users\brunosilva\AppData\Local\Programs\Python\Python312\Lib\logging\__init__.py", line 1538, in info File "C:\Users\brunosilva\AppData\Local\Programs\Python\Python312\Lib\logging\__init__.py", line 1800, in isEnabledFor TypeError: 'NoneType' object is not callable
错误根源
从报错栈可以看出,错误发生在程序退出阶段:Client实例的__del__方法被调用时,内部执行了destroy函数,而destroy中调用了logging.info。此时Python程序已进入退出流程,全局的logging模块已被提前销毁,导致isEnabledFor方法变为None,调用时触发TypeError。
近期突然出现问题的可能原因:
- Python版本更新(如升级到3.12),程序退出时模块销毁顺序发生变化
- Snap7库版本更新,
__del__或destroy的实现逻辑调整 - 脚本结构变更,导致Client实例的垃圾回收时机延后到程序退出阶段
正式修复方案
方案1:使用上下文管理器(推荐)
利用Snap7 Client的上下文管理器支持,确保实例在程序正常执行阶段就完成清理,避免__del__在退出阶段被触发:
import snap7 with snap7.client.Client() as plc: plc.connect("20.0.0.20", 0, 1) data = plc.db_read(1, 0, 1) x = snap7.util.get_bool(data, 0, 0) print(x) data = plc.db_read(1, 0, 1) x = snap7.util.get_bool(data, 0, 1) print(x) data = plc.db_read(1, 0, 1) x = snap7.util.get_bool(data, 0, 2) print(x) data = plc.db_read(1, 0, 1) x = snap7.util.get_bool(data, 0, 3) print(x) # with块结束后,实例自动执行close操作(包含disconnect和destroy),无需手动调用
方案2:显式控制生命周期
通过try-finally块确保实例在程序退出前完成所有清理操作,避免依赖__del__的自动调用:
import snap7 plc = snap7.client.Client() try: plc.connect("20.0.0.20", 0, 1) data = plc.db_read(1, 0, 1) x = snap7.util.get_bool(data, 0, 0) print(x) data = plc.db_read(1, 0, 1) x = snap7.util.get_bool(data, 0, 1) print(x) data = plc.db_read(1, 0, 1) x = snap7.util.get_bool(data, 0, 2) print(x) data = plc.db_read(1, 0, 1) x = snap7.util.get_bool(data, 0, 3) print(x) finally: plc.disconnect() plc.destroy() del plc
方案3:调整Snap7或Python版本
- 尝试升级Snap7到最新版本:
pip install --upgrade python-snap7 - 若升级后问题仍存在,可降级到之前正常工作的Snap7版本
- 若确认是Python版本问题,可临时降级到之前稳定的版本(如3.11)
临时方案说明
设置snap7.client.Client.__del__ = lambda self: None虽然能跳过错误,但可能导致PLC连接资源未被正确释放,长期使用存在资源泄漏风险,仅适用于临时测试,不建议在生产环境或集成项目中使用。
内容的提问来源于stack exchange,提问作者Arkeiro
相关产品推荐
相关产品推荐

