【问题标题】:Python decorator to refresh cursor instancePython 装饰器刷新游标实例
【发布时间】:2010-09-08 13:35:34
【问题描述】:

我有一种方法可以将数据保存在 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

如果不可能,如何以不同的方式解决这个问题?

感谢您的宝贵时间!

【问题讨论】:

  • 错误是self未定义

标签: python connection decorator


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    如果您显示您遇到的错误会有所帮助。不过,我可以猜一猜……

    装饰一个类的方法很难。 connectAndDisconnect 应该如何知道 self 应该是什么? connectAndDisconnect 是基类的静态方法,它在派生类创建时被调用,远早于派生类的任何实例被创建。

    有一个技巧可以让装饰者弄清楚self 应该是什么,但它是一个复杂的hack 和脆弱的方式,我将在最后解释。诀窍是,使用 class 作为装饰器,并使该类成为描述符(即定义 __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__ 将无法确定实例应该是什么。

    【讨论】:

    • 它似乎有效,它帮助我了解如何使用装饰器。谢谢!
    • 但是太长太混乱了,如果不是那么专业的人理解,最好是简短的回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-12
    • 2016-07-25
    • 2015-06-24
    • 1970-01-01
    • 1970-01-01
    • 2013-02-03
    • 2021-10-10
    相关资源
    最近更新 更多