用于刷新光标实例的 Python 装饰器

发布于 2024-09-18 23:56:23 字数 1004 浏览 4 评论 0原文

我有一种在数据库中保存数据的方法,还有一个装饰器来管理连接,但我不知道如何使其工作。

保存方法:

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 ?

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

谢谢您的宝贵时间!

I have a method to save data in DB, and a decorator to manage the connection, but I can't figure out how to make it work.

method to save:

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"
                                 )
        )

and I have here the inherited class with a function decorator that does not work.

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
....

Shown this...

How can I redefine DABase.__cursor from a decorator?

If is not possible, how to solve this problem in a different way?

Thank you for your time!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

狼性发作 2024-09-25 23:56:27

如果您显示您收到的错误,这将会有所帮助。但是,我可以猜测...

装饰类的方法很困难。 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__< /code> 被调用,因为有人尝试访问 d.save。这会将 _instance 变量设置为等于 d。然后调用 connectAndDisconnect.__call__ 并进行实际的装饰。

大多数时候这都是有效的。但它很脆弱。 如果您以“正常”方式(即通过实例)调用save,它才有效。如果您尝试做一些有趣的事情,例如调用 DA_Row.save(d)它不会工作,因为 connectAndDisconnect.__get__ 不会能够弄清楚实例应该是什么。

It would help if you showed the error that you're getting. However, I can take a guess...

Decorating a method of a class is hard. How is connectAndDisconnect supposed to know what self should be? connectAndDisconnect is a static method of the base class, which gets called when the derived class gets created, long before any instances of the derived class get created.

There's a trick which lets the decorator figure out what self should be, but it's a complicated hack and fragile in a way that I'll explain at the end. The trick is, use a class as the decorator, and make that class an descriptor (i.e. define __get__) to give you a chance to determine what self should be. In your case it would look something like:

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

The derived class is unchanged:

class DA_Row(DABase):
  @DABase.connectAndDisconnect
  def save(self):
    # ...

Now DA_Row.save is actually an instance of the connectAndDisconnect class. If d is a DA_Row object and someone calls d.save(), the first thing that happens is that connectAndDisconnect.__get__ gets called because someone tried to access d.save. This sets the _instance variable to equal d. Then connectAndDisconnect.__call__ gets called and the actual decoration takes place.

This works, most of the time. But it's fragile. It only works if you call save in the "normal" way, i.e. through an instance. If you try to do funny stuff like calling DA_Row.save(d) instead, it won't work because connectAndDisconnect.__get__ won't be able to figure out what the instance should be.

听你说爱我 2024-09-25 23:56:26

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

self is just a name like everything else, it does not magically appear like Java's this. You need to add it to your decorator. Try 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文