python sqlite3代码在全局空间中工作,但是当我将它放在函数中时会抛出错误

时间:2013-09-26 05:20:16

标签: python sqlite

我正在尝试从“Python标准库示例”一书中运行下面的'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.

为什么代码在函数中不起作用,如何使其工作?

3 个答案:

答案 0 :(得分: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并使其正常工作,只要您找到其他方法来序列化/反序列化您的对象。

尝试挑选一个不在顶层的课程,这是这个问题的根源。

答案 1 :(得分:1)

不要将类和函数放在stuff中。特别是,不要将MyObj放在那里。

如果您想使用if __name__=="__main__":条件,只需将的代码放在stuff内的类或函数中。

答案 2 :(得分: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()