2013-09-26 12 views
0

我試圖從書中「通過實例Python標準庫」運行follwoing「sqlite3_custom_type.py的榜樣。下面的代碼工作「開箱的」:蟒蛇sqlite3的代碼在全球空間,但thows錯誤,當我把它放在一個函數

import os 
import sqlite3 


db_filename = 'todo.db' 

db_is_new = not os.path.exists(db_filename) 

conn = sqlite3.connect(db_filename) 

if db_is_new: 
    print('need to create schema') 
else: 
    print('database exists, assume schema does to') 

conn.close() 

#import sqlite3 
try: 
    import cPickle as pickle 
except: 
    import pickle 

db_filename = 'todo.db' 

def adapter_func(obj): 
    """Convert from in-memory to storage representation. 
    """ 
    print 'adapter_func(%s)\n' % obj 
    return pickle.dumps(obj) 

def converter_func(data): 
    """Convert from storage to in-memory representation. 
    """ 
    print 'converter_func(%r)\n' % data 
    return pickle.loads(data) 


class MyObj(object): 
    def __init__(self, arg): 
     self.arg = arg 
    def __str__(self): 
     return 'MyObj(%r)' % self.arg 

# Register the functions for manipulating the type. 
sqlite3.register_adapter(MyObj, adapter_func) 
sqlite3.register_converter("MyObj", converter_func) 

# Create some objects to save. Use a list of tuples so 
# the sequence can be passed directly to executemany(). 
to_save = [ (MyObj('this is a value to save'),), 
      (MyObj(42),), 
      ] 

with sqlite3.connect(db_filename, 
        detect_types=sqlite3.PARSE_DECLTYPES) as conn: 
    # Create a table with column of type "MyObj" 
    conn.execute(""" 
    create table if not exists obj (
     id integer primary key autoincrement not null, 
     data MyObj 
    ) 
    """) 
    cursor = conn.cursor() 

    # Insert the objects into the database 
    cursor.executemany("insert into obj (data) values (?)", to_save) 

    # Query the database for the objects just saved 
    cursor.execute("select id, data from obj") 
    for obj_id, obj in cursor.fetchall(): 
     print 'Retrieved', obj_id, obj, type(obj) 
     print 

但如果我把所有的代碼在一個函數如

def stuff(): 
    ~same code as above but indented 
if __name__=="__main__": 
    stuff() 

然後我得到一個錯誤代碼:

cursor.executemany("insert into obj (data) values (?)", to_save) 
sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type. 

爲什麼不代碼工作的時候它是在一個功能,我怎樣才能使它發揮作用?

+0

插入語句位於代碼 – rtrwalker

+0

的第7行,用於在__main__中通過類而不是方法。和它的工作原理 – drabo2005

+0

的todo.db containt一些表格或尚未 – drabo2005

回答

0

按Tichodroma的答案,你需要拿出類和函數的所有stuff功能,包括sqlite3.register_adaptersqlite3.register_converter的。另外,作爲一般的文體觀點,your imports should go at the top of the script

下面的代碼工作:

import os 
import sqlite3 
try: 
    import cPickle as pickle 
except: 
    import pickle 

class MyObj(object): 
    def __init__(self, arg): 
     self.arg = arg 
    def __str__(self): 
     return 'MyObj(%r)' % self.arg 

def adapter_func(obj): 
    """Convert from in-memory to storage representation. 
    """ 
    print('adapter_func(%s)\n' % obj) 
    return pickle.dumps(obj) 

def converter_func(data): 
    """Convert from storage to in-memory representation. 
    """ 
    print('converter_func(%r)\n' % data) 
    return pickle.loads(data) 

# Register the functions for manipulating the type. 
sqlite3.register_adapter(MyObj, adapter_func) 
sqlite3.register_converter("MyObj", converter_func) 

def stuff(): 
    db_filename = 'todo.db' 

    db_is_new = not os.path.exists(db_filename) 

    conn = sqlite3.connect(db_filename) 

    if db_is_new: 
     print('need to create schema') 
    else: 
     print('database exists, assume schema does to') 

    conn.close() 

    db_filename = 'todo.db' 

    # Create some objects to save. Use a list of tuples so 
    # the sequence can be passed directly to executemany(). 
    to_save = [ (MyObj('this is a value to save'),), 
       (MyObj(42),), 
       ] 

    with sqlite3.connect(db_filename, 
         detect_types=sqlite3.PARSE_DECLTYPES) as conn: 
     # Create a table with column of type "MyObj" 
     conn.execute(""" 
     create table if not exists obj (
      id integer primary key autoincrement not null, 
      data MyObj 
     ) 
     """) 
     cursor = conn.cursor() 

     # Insert the objects into the database 
     cursor.executemany("insert into obj (data) values (?)", to_save) 

     # Query the database for the objects just saved 
     cursor.execute("select id, data from obj") 
     for obj_id, obj in cursor.fetchall(): 
      print('Retrieved', obj_id, obj, type(obj)) 
      print() 

if __name__ == "__main__": 
    stuff() 
1

不要把類和函數的stuff內。特別是,不要把MyObj放在裏面。

如果你想使用if __name__=="__main__":條件,只放就是類或stuff內部函數的代碼。

+0

我拿了'MyObj','adapter_func'和'converter_func'定義出來的'stuff'但我仍然得到同樣的錯誤在同一地點。 – rtrwalker

+0

它確實有效;我需要額外的(很明顯很多人會說)建議把我的'import pickle'放在我的任何函數定義之前。 – rtrwalker

2

按其他的答案,這是很好的風格來放置類模塊範圍。但是,在這種特殊情況下失敗的真正原因是因爲pickle.dumps(obj)調用嘗試挑選非模塊級別的類。

試試下面的代碼在你的adapter_func

def adapter_func(obj): 
    """Convert from in-memory to storage representation. 
    """ 
    try: 
     return pickle.dumps(obj) 
    except Exception, arg: 
     print 'Failed to pickle object [%s]' % arg 

你會看到一個錯誤,如時MyObj宣佈在裏面stuff如下:

Failed to pickle object [Can't pickle <class '__main__.MyObj'>: it's not found as __main__.MyObj] 

這是pickle的類的要求在模塊級別被宣佈爲described in the pickle documentation。 sqlite3模塊似乎正在壓縮適配器函數中引發的異常,而不是通過傳播它們導致無提示失敗。

您可以在stuff中聲明並註冊您的適配器和轉換器功能。拋開樣式問題,你也可以在你的函數中聲明你的MyObj,並讓它工作,只要你找到其他方法來串行化/反序列化你的對象。

這是嘗試醃製一個不在最高層的類,這是這個問題的根源。