我为SQLite制作了一个小的sql渲染器/包装器。主要想法是写:
execute( 'select * from talbe1 where col1={param1} and col2={param2}' )
而不是
execute( 'select * from table1 where col1=? and col2=?', (param1,param2) )
以下是代码:
import re
import sqlite3
class SQLWrapper():
def __init__(self, cursor):
self.cursor = cursor
def execute(self, sql):
regexp=re.compile(r'\{(.+?)\}')
sqlline = regexp.sub('?',sql)
statements = regexp.findall(sql)
varlist = tuple([ eval(_statement) for _statement in statements ])
self.cursor.execute(sqlline, varlist)
return self
def fetchall(self):
return self.cursor.fetchall()
#usage example
db = sqlite3.connect(':memory:')
cursor = db.cursor()
wrap = SQLWrapper(cursor)
wrap.execute('create table t1(a,b)')
for i in range(10):
wrap.execute('insert into t1(a,b) values({i}, {i*2})')
limit = 50
for line in wrap.execute('select * from t1 where b < {limit}').fetchall():
print line
它可以工作,但是当我将类SQLWrapper
移动到一个单独的模块(文件sqlwrap.py)并导入它时,程序崩溃了:
Traceback (most recent call last):
File "c:\py\module1.py", line 15, in <module>
wrap.execute('insert into t1(a,b) values({i}, {i*2})')
File "c:\py\sqlwrap.py", line 10, in execute
varlist = tuple([ eval(_statement) for _statement in statements ])
File "<string>", line 1, in <module>
NameError: name 'i' is not defined
即。变量i在其他模块中不可见。如何克服这个?
答案 0 :(得分:0)
这违反了大多数编程语言的正常范围规则。
通常你不希望你以某种方式调用的函数(或方法)神奇地用自己的变量做事。这意味着,只有那些变量值(!)才能被调用例程访问,您明确将其添加为参数。
当你在你的第一个代码(所有在一个模块中)移动你的for循环与i进入一个自己的函数将遇到相同的问题 - 我将是本函数的本地,而不是SQLwrapper可见。
范围规则有意将变量的访问权限限制为“在范围内”的变量,并且不允许访问“超出范围”的事物。因此,完成了一些信息隐藏,并降低了复杂性。
这意味着在某些情况下会有一些写入开销,但也可以通过抑制某些危险的做法和复杂性来节省程序。
当你打算使用SQLite(或MySQL)时,我会推荐类似的东西:
execute( 'select * from table1 where col1=@param1 and col2=@param2', {'param1': param1, 'param2': param2} )
因此,您拥有更易阅读且易于理解的版本,但没有您遇到的范围问题。 @ -prefix适用于SQLite,我也知道,也适用于MySQL - 但它是特定于数据库的(遗憾的是,SQL没有将其标准化)。在sqlite3-module的文档中,使用了另一个前缀':',这也适用于SQLite,但我不知道在哪个DB上。
请参阅:sqlite3.Cursor.execute documentation
顺便说一下,如果你想减少一点写作开销,你可以写一些这样的包装:def myExcecute(sql, **params):
self.cursor.execute(sql, params)
因此,您可以以较少的开销(以及较少的括号)调用execute:
myExecute( 'select * from table1 where col1=@param1 and col2=@param2', param1=param1, param2=param2 )