Skip to main content
 首页 » 编程设计

python之覆盖外部库中的 python 实例方法

2025年05月04日11pengyingh

我已经为数据库连接编写了一个上下文管理器。 我想重写来自外部类的方法(cx_oracle.Cursor 中的“执行”),以在将查询传递给数据库之前删除任何无关的绑定(bind)变量(否则它们会导致 DatabaseError)。他们为什么会在那里开始的问题是正交的。

以下有效,但我想知道我是否在这里正确使用了 _getattribute_(之前真的没有借口使用它) .

我也“洗耳恭听”……嗯……如果有人对如何从这个外部库中覆盖这个方法有更好的建议。

谢谢。我正在使用 python 2.7

import cx_Oracle 
from contextlib import contextmanager 
 
class Cursor(cx_Oracle.Cursor): 
    """A wrapper for cx_Oracle cursors that will drop extraneous bind variables passed to in""" 
 
    def __init__(self, curs): 
        self.curs = curs 
 
    def execute(self, sql, *args, **kwargs): 
        params = {} 
        print("in execute, args[0] = [%s]" % str(args[0])) 
        if len(args) == 1 and isinstance(args[0], dict): 
            for bv in args[0].keys(): 
                if ':%s' % bv in sql: 
                    params[bv] = args[0][bv] 
            print('params = %s' % str(params)) 
        else: 
            return self.curs.execute(sql, *args, **kwargs) 
 
        return self.curs.execute(sql, params) 
 
 
    def __getattribute__(self, name): 
        if name == 'execute': 
            return object.__getattribute__(self, name) 
        elif name == 'curs': 
            return object.__getattribute__(self, 'curs') 
        else: 
            curs = object.__getattribute__(self, 'curs') 
            return cx_Oracle.Cursor.__getattribute__(curs, name) 
 
 
@contextmanager 
def db_conn(): 
 
    pool = cx_Oracle.SessionPool("user", "pwd", "database", min=2, max=10, increment=1, threaded=True) 
    conn = pool.acquire() 
 
    try: 
        yield Cursor(conn.cursor()) 
    except: 
        conn.rollback() 
        raise 
    else: 
        conn.commit() 
    finally: 
        pool.release(conn) 
 
 
if __name__ == '__main__': 
 
    with db_conn() as curs: 
        curs.execute('select * from dual where 1 = :a', {'a':1, 'b':2}) 
        print(curs.fetchall()) 

请您参考如下方法:

如果您使用的是 __getattr__ 方法,而不是 __getattribute__,则您不必在自己的类中对名称进行特殊区分。如果无法通过正常方式找到属性,它只会查看 __getattr__。

类似于:

def __getattr__(self, name): 
    return getattr(self.curs, name) 

您需要将 class Cursor(cx_Oracle.Cursor): 更改为 class Cursor(object):。通过子类化来做你想做的事情很棘手,因为游标是由数据库连接的方法创建的。您也可以子类化 SessionPool,以便其 cursor 方法返回您的自定义游标实例,但这可能不值得付出努力。