Python 装饰器刷新游标实例
我有一个方法用来把数据保存到数据库里,还有一个装饰器用来管理连接,但我不知道怎么让它们一起工作。
保存数据的方法是:
class DA_Row(DABase):
@DABase.connectAndDisconnect
def save(self):
"""
Guarda el spin en la base de datos
"""
self.__cursor.callproc('sp_insert_row', (
"value 1",
"value 2"
)
)
这里有一个继承的类,里面有一个函数装饰器,但它没有正常工作。
class DABase():
def __init__(self):
self.__cursor = None
@staticmethod
def connectAndDisconnect(func):
def deco(*args):
returnValue = None
self.DBconnect()
try:
self.__cursor = self.db.cursor()
returnValue = func(*args)
finally:
self.desconectarDB()
return returnValue
return deco
....
我展示了这个...
我该如何从装饰器中重新定义 DABase.__cursor
呢?
如果不行,那有没有其他方法可以解决这个问题?
谢谢你的时间!
2 个回答
如果你能把遇到的错误信息给我看就更好了。不过,我可以猜一下...
给一个类的方法加装饰器是比较复杂的。像 connectAndDisconnect
这样的方法怎么知道 self
应该是什么呢?connectAndDisconnect
是基类的一个 静态方法,它在派生类创建的时候就会被调用,这个时候派生类的实例还没创建。
有一个技巧可以让装饰器知道 self
应该是什么,但这个方法比较复杂,而且有点脆弱,我会在最后解释。这个技巧是,使用一个 类 作为装饰器,并让这个类成为一个描述符(也就是定义 __get__
方法),这样你就可以有机会确定 self
应该是什么。在你的情况下,代码大概是这样的:
class DABase(object):
def __init__(self):
self.__cursor = None
class connectAndDisconnect(object):
def __init__(self, method):
self._method = method # method is the thing being decorated
# note that it's an *unbound* method
self._instance = None # no way to know what the instance is yet
def __get__(self, instance, owner):
'This will be called when the decorated method is accessed'
self._instance = instance
return self
def __call__(self, *args):
'This is where the actual decoration takes place'
returnValue = None
# 'self' is the connectAndDisconnect object. 'self._instance' is the decorated object.
self._instance.DBConnect()
try:
self._instance.__cursor = self._instance.db.cursor()
# Since self._method is unbound, we have to pass the instance explicitly
returnValue = self._method(self._instance, *args)
finally:
self._instance.desconectarDB()
return returnValue
派生类保持不变:
class DA_Row(DABase):
@DABase.connectAndDisconnect
def save(self):
# ...
现在 DA_Row.save
实际上是 connectAndDisconnect
类的一个实例。如果 d
是一个 DA_Row
对象,且有人调用 d.save()
,首先发生的事情是 connectAndDisconnect.__get__
被调用,因为有人试图访问 d.save
。这时会把 _instance
变量设置为 d
。然后 connectAndDisconnect.__call__
被调用,实际的装饰过程就开始了。
这个方法大部分时候都能工作。但它有点脆弱。它 仅仅 在你以“正常”的方式调用 save
时有效,也就是说通过一个实例来调用。如果你尝试用其他方式,比如直接调用 DA_Row.save(d)
,那就不行,因为 connectAndDisconnect.__get__
无法确定实例应该是什么。
self
只是一个名字,就像其他所有名字一样,它并不是像Java中的 this
那样神奇地出现。你需要把它加到你的装饰器里。试试这个:
@staticmethod
def connectAndDisconnect(func):
# deco will be a method, so it needs self (ie a DA_Row instance)
def deco(self, *args):
returnValue = None
self.DBconnect()
try:
self.__cursor = self.db.cursor()
# func was supposed to be a method to, so it needs self
returnValue = func(self, *args)
finally:
self.desconectarDB()
return returnValue
return deco