ZetCode

Python sqlite3.Cursor.setinputsizes 方法

上次修改时间:2025 年 4 月 15 日

本指南探讨 Python 的 sqlite3.Cursor.setinputsizes 方法,它是 DB-API 2.0 规范的一部分,但在 SQLite 中未实现。

基本定义

setinputsizes 方法在 Python 的 DB-API 2.0 中定义为预定义参数绑定的内存区域的一种方式。 它旨在优化同一语句的重复执行。

在 SQLite 的实现中,此方法什么也不做,因为 SQLite 动态处理参数绑定。 该方法的存在是为了 API 兼容性,但不起作用。

方法签名

该方法的签名很简单:setinputsizes(sizes),其中 sizes 可以是序列或 None。 sizes 参数指定预期的数据类型。

尽管可以调用,但该方法在 SQLite 中不执行任何操作。 它的存在是为了保持与 DB-API 2.0 规范的兼容性。

基本用法

此示例演示了使用不同参数类型调用该方法。 尽管进行了调用,但它们对 SQLite 操作没有影响。

basic_usage.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    with conn.cursor() as cur:
        # These calls do nothing in SQLite
        cur.setinputsizes(None)
        cur.setinputsizes([sqlite3.TEXT, sqlite3.INTEGER])
        cur.setinputsizes(50)  # Arbitrary size
        
        # Execute a query normally
        cur.execute("CREATE TABLE test (id INTEGER, name TEXT)")
        cur.execute("INSERT INTO test VALUES (?, ?)", (1, 'Alice'))

该示例表明,可以调用 setinputsizes,但不会影响后续操作。 SQLite 动态处理参数绑定。

使用 execute

此示例尝试在执行查询之前使用 setinputsizes。 该方法调用对执行没有影响。

with_execute.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    with conn.cursor() as cur:
        cur.execute("CREATE TABLE data (id INTEGER, value REAL)")
        
        # Set input sizes (no effect)
        cur.setinputsizes([sqlite3.INTEGER, sqlite3.REAL])
        
        # Insert data works the same with or without setinputsizes
        cur.execute("INSERT INTO data VALUES (?, ?)", (1, 3.14159))
        
        # Verify insertion
        cur.execute("SELECT * FROM data")
        print(cur.fetchone())  # (1, 3.14159)

无论是否调用 setinputsizes,数据插入的工作方式都相同。 SQLite 在执行时确定参数类型。

多种参数类型

此示例表明,SQLite 忽略提供给 setinputsizes 的类型提示,并自动处理类型转换。

multiple_types.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    with conn.cursor() as cur:
        cur.execute("CREATE TABLE items (id INTEGER, name TEXT, price REAL)")
        
        # Set input sizes for different types (ignored)
        cur.setinputsizes([sqlite3.INTEGER, sqlite3.TEXT, sqlite3.REAL])
        
        # Insert with automatic type conversion
        cur.execute("INSERT INTO items VALUES (?, ?, ?)", 
                   ('1', 42.99, '3.50'))  # Note reversed types
        
        # The values are stored correctly despite type hints
        cur.execute("SELECT * FROM items")
        print(cur.fetchone())  # (1, '42.99', 3.5)

无论 setinputsizes 调用如何,SQLite 都会执行类型转换。 该方法不会在 SQLite 中强制执行或影响类型处理。

使用 executemany

此示例演示了 setinputsizes 对使用 executemany 的批量操作没有影响。

with_executemany.py
import sqlite3

data = [
    (1, 'Apple', 0.99),
    (2, 'Banana', 0.59),
    (3, 'Cherry', 1.99)
]

with sqlite3.connect(':memory:') as conn:
    with conn.cursor() as cur:
        cur.execute("CREATE TABLE products (id INTEGER, name TEXT, price REAL)")
        
        # Set input sizes (no effect)
        cur.setinputsizes([sqlite3.INTEGER, sqlite3.TEXT, sqlite3.REAL])
        
        # Batch insert works normally
        cur.executemany("INSERT INTO products VALUES (?, ?, ?)", data)
        
        # Verify all rows inserted
        cur.execute("SELECT COUNT(*) FROM products")
        print(cur.fetchone()[0])  # 3

无论 setinputsizes 调用如何,executemany 操作都会正常进行。 SQLite 动态处理每个参数集。

使用自定义类型

此示例表明,setinputsizes 不会影响 SQLite 中的自定义类型适配器。

custom_types.py
import sqlite3
import datetime

# Register custom adapter
sqlite3.register_adapter(datetime.date, lambda d: d.isoformat())

with sqlite3.connect(':memory:') as conn:
    with conn.cursor() as cur:
        cur.execute("CREATE TABLE events (id INTEGER, date TEXT)")
        
        # Set input sizes (ignored)
        cur.setinputsizes([sqlite3.INTEGER, sqlite3.TEXT])
        
        # Custom type conversion still works
        today = datetime.date.today()
        cur.execute("INSERT INTO events VALUES (?, ?)", (1, today))
        
        # Verify date stored correctly
        cur.execute("SELECT date FROM events WHERE id = 1")
        print(cur.fetchone()[0])  # ISO formatted date

无论 setinputsizes 调用如何,自定义日期适配器都能正常工作。 SQLite 的类型适配系统独立于此方法运行。

性能比较

此示例演示了 setinputsizes 在 SQLite 中没有提供任何性能优势,这与其他一些数据库系统不同。

performance.py
import sqlite3
import time

def time_inserts(use_setinputsizes):
    with sqlite3.connect(':memory:') as conn:
        with conn.cursor() as cur:
            cur.execute("CREATE TABLE nums (n INTEGER)")
            
            if use_setinputsizes:
                cur.setinputsizes([sqlite3.INTEGER])
            
            start = time.time()
            for i in range(1000):
                cur.execute("INSERT INTO nums VALUES (?)", (i,))
            conn.commit()
            return time.time() - start

# Compare execution times
time_with = time_inserts(True)
time_without = time_inserts(False)

print(f"With setinputsizes: {time_with:.4f}s")
print(f"Without setinputsizes: {time_without:.4f}s")

执行时间将几乎相同,表明 setinputsizes 在 SQLite 中没有提供性能优化。

错误处理

此示例表明,setinputsizes 不会验证参数或影响 SQLite 中的错误处理。

error_handling.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    with conn.cursor() as cur:
        cur.execute("CREATE TABLE test (id INTEGER PRIMARY KEY, data TEXT)")
        
        # These calls don't affect error handling
        cur.setinputsizes([sqlite3.INTEGER, sqlite3.TEXT])
        cur.setinputsizes("invalid")  # Non-standard parameter
        
        try:
            # This will still raise an error
            cur.execute("INSERT INTO test VALUES (?, ?)", ("text", 123))
        except sqlite3.InterfaceError as e:
            print(f"Error occurred: {e}")

该示例演示了 setinputsizes 不会阻止或影响 SQLite 中与类型相关的错误。 错误在执行期间引发。

最佳实践

资料来源

作者

我叫 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程