【问题标题】:Can't decorate third party read-only function, how to wrap it for additional functionality?无法装饰第三方只读功能,如何包装它以获得附加功能?
【发布时间】:2019-08-20 14:55:36
【问题描述】:

我有以下(高度简化的)装饰器:

def log_and_execute(func):
    def wrapper(*args, **kwargs):
        print(*args, **kwargs)
        return func(*args, **kwargs)
    return wrapper

我想用这个来装饰pyodbc.connect.cursor

由于我显然无法编辑源代码来执行此操作,因此我尝试这样做:

import pyodbc

connection = pyodbc.connect("connection_string_here")
cursor = connection.cursor()

cursor.execute = log_and_execute(cursor.execute)

但我收到以下错误:

AttributeError: 'pyodbc.Cursor' object attribute 'execute' is read-only

我应该怎么做,这样我就不必更改所有已经存在的cursor.execute 调用?

【问题讨论】:

  • 你不能。为什么不创建一个仅代理存储为属性的游标的包装器对象?
  • @MartijnPieters 我不确定您的解决方案是什么意思。我正在尝试这样做,这样我就不必更改所有现有的 cursor.execute 调用。
  • Cursor 中使用的 pyodbc 类完全用 C 编码,不能进行猴子补丁。您唯一的选择是创建自己的类,该类使用__getattr__ 和更多__dunder__ 特殊方法来代理对包装的游标实例的调用(您需要额外的特殊方法来支持迭代和上下文管理器支持pyodbc 游标实现)。 __getattr__ 方法只是从游标实例中获取相同的属性并返回它。这就是您可以应用额外包装的关键,例如打印。
  • @MartijnPieters 你想将你的评论扩展到一个答案,它显示了一个示例类吗?

标签: python python-3.x wrapper pyodbc python-decorators


【解决方案1】:

您不能更改 pyodbc Cursor 类,它是用 C 编写的,不允许设置属性。

你最多可以写一个包装类:

class CursorWrapper:
    def __init__(self, cursor):
        self.cursor = cursor

    def execute(self, *args, **kwargs):
        print(*args, **kwargs)
        return self.cursor.execute(*args, **kwargs)

    def __getattr__(self, attr):
        return getattr(self.cursor, attr)

    def __iter__(self):
        return iter(self.cursor)

    def __enter__(self):
        return self.cursor.__enter__()

    def __exit__(self, *args, **kwargs):
        return self.cursor.__exit__(*args, **kwargs)

然后每次将光标包裹在该类中:

cursor = CursorWrapper(connection.cursor())

【讨论】:

  • 非常感谢,这是一个很好的解决方案!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-14
  • 2011-01-30
  • 2015-07-07
  • 2021-12-05
  • 2015-05-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多