我为数据库连接编写了一个上下文管理器。 我想从外部类(cx_oracle.Cursor中的'execute')覆盖一个方法,在将查询传递给数据库之前删除任何无关的绑定变量(否则它们会导致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())
答案 0 :(得分:1)
如果您使用的是__getattr__
方法,而不是__getattribute__
,那么您不必在特殊情况下使用您自己班级中的名称。如果它无法通过正常方式找到属性,它只会查看__getattr__
。
类似的东西:
def __getattr__(self, name):
return getattr(self.curs, name)
您需要将class Cursor(cx_Oracle.Cursor):
更改为class Cursor(object):
。通过子类化做你正在尝试的事情是很棘手的,因为游标是由数据库连接的方法创建的。您也可以将SessionPool子类化,以便它的cursor
方法返回您的自定义游标实例,但它可能不值得付出努力。