我有一个用于数据库连接的类作为上下文管理器:
class Database:
def __init__(self):
self._conn = psycopg2.connect(host=os.environ['DB_SERVER'],
database=os.environ['DB_NAME'],
user=os.environ['DB_USER'],
password=os.environ['DB_PASSWORD'])
self._cursor = self._conn.cursor()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
@property
def connection(self):
return self._conn
@property
def cursor(self):
return self._cursor
def commit(self):
self.connection.commit()
def close(self, commit=True):
if commit:
self.commit()
self.cursor.close()
self.connection.close()
def execute(self, sql, params=None):
self.cursor.execute(sql, params or ())
def fetchall(self):
return self.cursor.fetchall()
def fetchone(self):
return self.cursor.fetchone()
def query(self, sql, params=None):
self.cursor.execute(sql, params or ())
return self.fetchall()
字符串
我想用它来装饰。我把decorator写为function with_connection,它工作得很好。
def with_connection(func):
def wrapper(*args, **kwargs):
with Database() as db:
return func(db, *args, **kwargs)
return wrapper
型
我使用它与其他功能如下:
@with_connection
def selectfunc(conn, *args, **kwargs):
...
型
现在我想在Database类中实现 call magic方法,并使用类作为装饰器,而不是使用单独的函数,我想我需要这样的东西:
def __call__(self, f):
@functools.wraps(f)
def decorated(*args, **kwds):
with self as db:
return f(db, *args, **kwds)
return decorated
型
首先我得到了TypeError:init()接受1个位置参数,但给出了2个。因此,我在init方法中添加了 *args和**kwargs,但随后我得到了TypeError:call()缺少1个必需的位置参数:“f”
我希望能得到一些关于如何正确实现调用方法以及如何使用这个类作为装饰器的帮助。
1条答案
按热度按时间bttbmeg01#
您的类是正确的,实现
__call__
将类转换为装饰器是正常的。为了完整起见,这里有Database
类。我添加了一个connect方法来分离初始化和实际连接到数据库,这确保了它发生在更接近你的函数使用数据库的时候。字符串
你得到的异常是因为你是这样使用它的:
型
而不是像这样:
型
你需要传递一个示例,而不是类本身。在第一个例子中,
__init__
被调用,Python试图将self和修饰函数传递给它,这是一个太多的参数。如果你喜欢旧的函数名,你也可以这样做:
型
如果你遵循这种方法,一定要分离初始化和连接,否则你会遇到问题。