簡體   English   中英

如何在Python中從被調用模塊訪問調用模塊名稱空間?

[英]How to access to calling module namespace from called module in Python?

我為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在其他模塊中不可見。 如何克服呢?

這違反了大多數編程語言的正常范圍規則。

通常,您不希望通過某種方式調用的函數(或方法)以自己的變量神奇地執行操作。 這意味着,只有那些變量值(!)才能被調用例程訪問,您已將其顯式添加為參數。

當您在第一個代碼中(全部在一個模塊中)將帶i的for循環移動到自己的函數中時,將會遇到相同的問題-比起我,我將對該函數而言是本地的,並且對SQLwrapper不可見。

范圍規則有意地將變量的訪問限制為“范圍內”的變量,並且不授予對“范圍外”的變量的訪問。 因此完成了一些信息隱藏並降低了復雜性。

這意味着在某些情況下會產生一些寫開銷,但同時也通過抑制某些危險的做法和復雜性,使程序更加節省。

當您僅打算使用SQLite(或MySQL)時,我建議使用類似的方法:

execute( 'select * from table1 where col1=@param1 and col2=@param2', {'param1': param1, 'param2': param2} )

因此,您擁有一個更具可讀性和可理解性的版本,但沒有遇到遇到的范圍問題。 @前綴可以在SQLite上使用,而且據我所知,在MySQL上也可以使用-但這是特定於數據庫的(很遺憾,SQL尚未對其進行標准化)。 在sqlite3-module的文檔中,使用了另一個前綴“:”,這在SQLite中也可以使用,但是我不知道在哪個其他數據庫上。

請參閱: sqlite3.Cursor.execute文檔

順便說一句,如果您想稍微減少編寫開銷,可以編寫一些包裝器:

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

因此,您可以以更少的開銷(和更少的括號)調用execute:

myExecute( 'select * from table1 where col1=@param1 and col2=@param2', param1=param1, param2=param2 )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM