0

本「Python Standard Library by Example」から次の「sqlite3_custom_type.py」の例を実行しようとしています。次のコードは、「箱から出してすぐに」機能します。

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.

コードが関数内にあると機能しないのはなぜですか?どうすれば機能させることができますか?

4

3 に答える 3

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 のドキュメントで説明されているように、pickle さpickleれるクラスがモジュール レベルで宣言されている必要があります。sqlite3 モジュールは、アダプター関数で発生した例外を伝播するのではなく、黙ってエラーを発生させるのではなく、押しつぶしているように見えます。

内でアダプター関数とコンバーター関数を宣言して登録できますstuffMyObjスタイルの問題は別として、オブジェクトをシリアル化/逆シリアル化する他の方法を見つける限り、関数内で宣言して機能させることもできます。

この問題の根源は、最上位にないクラスをピクルしようとする試みです。

于 2013-09-27T01:16:44.650 に答える
1

クラスと関数を の中に入れないでくださいstuff。特に入れないでくださいMyObj

条件を使用する場合 は、クラスまたは関数ではないif __name__=="__main__":コードのみを の中に入れます。stuff

于 2013-09-26T05:52:57.653 に答える