Python装饰器刷新游标实例

时间:2010-09-08 13:35:34

标签: python connection decorator

我有一种方法可以在DB中保存数据,还有一个装饰器来管理连接,但我无法弄清楚如何使它工作。

保存方法:

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 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:2)

如果您显示出错误,那将会有所帮助。但是,我可以猜一猜......

装饰课程的方法很难。 connectAndDisconnect如何知道self应该是什么? connectAndDisconnect是基类的静态方法,在创建派生类时,在派生类的任何实例创建之前很久就会调用它。 / p>

有一个技巧可以让装饰者找出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类的一个实例。如果dDA_Row个对象且有人调用d.save(),则首先发生的是connectAndDisconnect.__get__被调用,因为有人试图访问d.save。这会将_instance变量设置为等于d。然后调用connectAndDisconnect.__call__并进行实际装饰。

大部分时间都可以使用。但它很脆弱。如果您以“正常”方式(即通过实例)调用save,则有效。如果您尝试执行有趣的操作,例如调用DA_Row.save(d)将无效,因为connectAndDisconnect.__get__将无法确定实例应该是什么。