2014-10-16 122 views
1

我为SQLite做了一个很小的sql渲染器/包装器。主要的想法是写:如何访问从Python中的调用模块调用模块名称空间?

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.e.变量i在其他模块中不可见。如何克服这一点?

回答

0

这违背了大多数编程语言的正常范围规则。

通常情况下,你不希望你调用的函数(或方法)以某种方式神奇地用自己的变量做事情。这意味着,只有那些变量值(!)可以访问被调用的例程,您明确将其添加为参数。当你在你的第一个代码中(全部在一个模块中)将你的for循环与我一起移动到一个自己的函数中时,会遇到同样的问题 - 比我本地化这个函数并且对SQLwrapper不可见。

范围规则有意限制变量对“范围内”的访问,并且不允许访问“超出范围”的内容。因此,一些信息隐藏完成并且复杂度降低。

这意味着在某些情况下会产生一些写入开销,但也会通过抑制一些危险的做法和复杂性来节省程序。

我建议这样的事情,当你只打算使用SQLite(或MySQL):

execute('select * from table1 where [email protected] and [email protected]', {'param1': param1, 'param2': param2}) 

因此,你有一个更易于阅读和理解的版本,但没有范围的问题,你遇到过。 @prefix适用于SQLite,尽管我也知道,也是在MySQL中 - 但它是数据库特定的(可悲的是,SQL没有标准化)。在sqlite3模块的文档中使用了另一个前缀':',这也适用于SQLite,但我不知道其他哪个数据库。

参见:sqlite3.Cursor.execute documentation

顺便说一句,如果你想减少开销,你的写作一点点,你可以写一些包装这样的:

def myExcecute(sql, **params): 
    self.cursor.execute(sql, params) 

因此,你可以调用与少一点的开销执行(和更少的支架):

myExecute('select * from table1 where [email protected] and [email protected]', param1=param1, param2=param2)