ZetCode

Python sqlite3.Row.__getitem__ 方法

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

本综合指南探讨了 Python 的 sqlite3.Row.__getitem__ 方法,该方法提供了对行值的索引访问。我们将涵盖基本用法、索引选项和实际示例。

基本定义

sqlite3.Row.__getitem__ 方法允许通过索引或列名访问行值。它是基于索引和基于名称的行数据访问的底层实现。

主要特点:它支持用于位置访问的整数索引和用于列名访问的字符串键。当在 Row 对象上使用方括号表示法时,它在内部使用。

基本行访问

这是 __getitem__ 的最简单用法,可以通过索引和列名访问行值。

basic_access.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    
    cursor.execute('''CREATE TABLE users (id INTEGER, name TEXT)''')
    cursor.execute("INSERT INTO users VALUES (1, 'Alice')")
    
    cursor.execute("SELECT * FROM users")
    row = cursor.fetchone()
    
    # Access by index
    print(row.__getitem__(0))  # 1
    
    # Access by column name
    print(row.__getitem__('name'))  # Alice

此示例显示了使用 __getitem__ 基于索引和基于名称的访问。 row_factory 设置为 sqlite3.Row 以进行命名访问。

通常,你会使用 row[0]row['name'] 语法,这些语法在内部调用 __getitem__

访问多个列

此示例演示了如何在循环中使用 __getitem__ 访问多个列。

multiple_columns.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    
    cursor.execute('''CREATE TABLE products
                     (id INTEGER, name TEXT, price REAL)''')
    cursor.execute("INSERT INTO products VALUES (1, 'Laptop', 999.99)")
    
    cursor.execute("SELECT * FROM products")
    row = cursor.fetchone()
    
    # Access all columns by name
    for col in row.keys():
        print(f"{col}: {row.__getitem__(col)}")

该示例展示了如何遍历所有列并使用 __getitem__ 和列名访问它们的值。 keys 方法提供列名。

当你需要处理所有列而事先不知道它们的名称时,此模式非常有用。

处理缺失的列

此示例显示了尝试使用 __getitem__ 访问不存在的列时会发生什么。

missing_columns.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    
    cursor.execute('''CREATE TABLE test (id INTEGER)''')
    cursor.execute("INSERT INTO test VALUES (1)")
    
    cursor.execute("SELECT * FROM test")
    row = cursor.fetchone()
    
    try:
        # Access non-existent column
        print(row.__getitem__('nonexistent'))
    except IndexError as e:
        print(f"Error: {e}")

尝试使用 __getitem__ 访问不存在的列会引发 IndexError。此行为与 Python 的序列协议一致。

在处理动态查询时,始终使用 keys 检查列是否存在或处理潜在的异常。

与整数索引一起使用

此示例演示了如何将 __getitem__ 与整数索引一起使用以进行位置访问。

integer_indices.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    cursor = conn.cursor()
    
    cursor.execute('''CREATE TABLE data (a INTEGER, b INTEGER, c INTEGER)''')
    cursor.execute("INSERT INTO data VALUES (10, 20, 30)")
    
    cursor.execute("SELECT * FROM data")
    row = cursor.fetchone()
    
    # Access by position
    print(row.__getitem__(0))  # 10
    print(row.__getitem__(2))  # 30
    
    # Negative indices work too
    print(row.__getitem__(-1))  # 30

该示例显示了使用整数索引的标准序列样式访问。负索引按预期工作,从末尾开始计数。

位置访问比命名访问更快,但可读性较差,尤其是在列很多的情况下。

与其他 Row 方法结合使用

此示例显示了 __getitem__ 如何与其他 Row 方法(如 keysvalues)交互。

combined_methods.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    
    cursor.execute('''CREATE TABLE events
                     (id INTEGER, name TEXT, date TEXT)''')
    cursor.execute("INSERT INTO events VALUES (1, 'Meeting', '2025-01-01')")
    
    cursor.execute("SELECT * FROM events")
    row = cursor.fetchone()
    
    # Combine with keys() and values()
    for i, col in enumerate(row.keys()):
        print(f"{col}: {row.__getitem__(i)} == {row.__getitem__(col)}")

该示例演示了当引用同一列时,基于索引和基于名称的访问返回相同的值。顺序与查询的列顺序匹配。

这种一致性在构建动态数据处理管道时非常重要。

性能比较

此示例比较了 __getitem__ 与直接属性访问的性能。

performance.py
import sqlite3
import timeit

with sqlite3.connect(':memory:') as conn:
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    
    cursor.execute('''CREATE TABLE perf (a INTEGER, b INTEGER)''')
    cursor.execute("INSERT INTO perf VALUES (1, 2)")
    
    cursor.execute("SELECT * FROM perf")
    row = cursor.fetchone()
    
    # Time __getitem__ access
    t1 = timeit.timeit(lambda: row.__getitem__('a'), number=100000)
    
    # Time direct attribute access
    t2 = timeit.timeit(lambda: row['a'], number=100000)
    
    print(f"__getitem__: {t1:.3f}s")
    print(f"Direct access: {t2:.3f}s")

该示例表明,直接方括号访问 (row['a']) 比直接调用 __getitem__ 略快。这两种方法都非常有效。

在大多数应用程序中,性能差异可以忽略不计,因此更喜欢更具可读性的语法。

自定义 Row 子类

此高级示例演示了如何创建扩展 __getitem__ 行为的自定义 Row 子类。

custom_row.py
import sqlite3

class CustomRow(sqlite3.Row):
    def __getitem__(self, key):
        val = super().__getitem__(key)
        return f"Custom: {val}"

with sqlite3.connect(':memory:') as conn:
    conn.row_factory = CustomRow
    cursor = conn.cursor()
    
    cursor.execute('''CREATE TABLE items (id INTEGER, name TEXT)''')
    cursor.execute("INSERT INTO items VALUES (1, 'Widget')")
    
    cursor.execute("SELECT * FROM items")
    row = cursor.fetchone()
    
    print(row.__getitem__('name'))  # Custom: Widget
    print(row['id'])  # Custom: 1

该示例展示了如何子类化 sqlite3.Row 并修改 __getitem__ 行为。所有访问方法都继承了新行为。

此技术对于向行访问操作添加验证、转换或日志记录非常强大。

最佳实践

资料来源

作者

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

列出所有 Python 教程