Python实现SQL查询包装函数报错:'function' object has no attribute 'cursor'
问题分析与修复
错误根源
你的装饰器写法犯了两个核心错误:
- 装饰器参数传递错误:
sql_select是类的实例方法,需要接收self参数,但用@sql_select装饰test时,Python会把test函数当作第一个参数传给sql_select,导致sql_select里的self变成了test函数对象,后续访问self.cursor自然会报错'function' object has no attribute 'cursor'。 - 未正确调用被装饰方法:你直接把
func(即test函数对象)塞进了SQL模板,没有执行它来获取实际的SQL语句,而且test作为实例方法需要接收self参数才能正常执行。
修复后的代码
import sqlite3 import threading class DatabaseManagment(): def __init__(self) -> None: self.con = sqlite3.connect("test.db") self.cursor = self.con.cursor() self.lock = threading.Lock() # 改成静态方法的装饰器,避免实例绑定问题 @staticmethod def sql_select(func): def inner(self): # 调用被装饰的实例方法,传入self获取SQL语句 sql = func(self) # 加锁保证线程安全 with self.lock: self.cursor.execute(sql) return self.cursor.fetchall() return inner @sql_select def test(self): return "SELECT * FROM App_price"
关键改动说明
- 将
sql_select改为静态方法:这样在类定义阶段装饰test时,不会涉及实例的self绑定问题,能正确接收被装饰的函数func。 - 让
inner函数接收self参数:作为实例方法的包装,inner需要访问实例的cursor和lock,同时通过func(self)调用被装饰的方法,获取返回的SQL语句。 - 加入线程锁:利用你初始化的
lock,通过with语句自动管理锁的获取和释放,避免多线程环境下的数据库操作冲突。
扩展优化(可选)
如果需要支持带参数的SQL查询(比如SELECT * FROM App_price WHERE id = ?),可以修改装饰器和被装饰方法,传入参数:
@staticmethod def sql_select(func): def inner(self, *args, **kwargs): sql = func(self, *args, **kwargs) with self.lock: self.cursor.execute(sql, args) return self.cursor.fetchall() return inner @sql_select def get_price_by_id(self, price_id): return "SELECT * FROM App_price WHERE id = ?"
这样调用db.get_price_by_id(1)时,参数会被自动传递给SQL的占位符,更灵活实用。
内容的提问来源于stack exchange,提问作者logan_9997
相关产品推荐
相关产品推荐

