ZetCode

Python sqlite3.Row.__iter__ 方法

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

本综合指南探讨 Python 的 sqlite3.Row.__iter__ 方法,该方法可以迭代数据库行。我们将介绍基本用法、实际示例以及与其他 Python 功能的集成。

基本定义

sqlite3.Row.__iter__ 方法允许迭代数据库行中的值。当您迭代 Row 对象时,它会被自动调用。

主要特性:它返回列值的迭代器,保留列顺序,并且适用于所有标准迭代工具。该方法可以直接访问行数据,而无需显式索引。

基本行迭代

这是使用 __iter__ 迭代行值的最简单用法。

basic_iteration.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()
    
    # Iterate over row values
    for value in row:
        print(value)

此示例创建一个包含一行的内存数据库。for 循环隐式调用 __iter__ 来访问每个列值。

输出显示行中的两个值:1'Alice'。迭代顺序与表定义中的列顺序匹配。

解包行值

__iter__ 方法支持行值的元组解包。

unpacking.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 (101, 'Laptop', 999.99)")
    
    cursor.execute("SELECT * FROM products")
    row = cursor.fetchone()
    
    # Unpack row values
    id, name, price = row
    print(f"Product {id}: {name} costs ${price:.2f}")

此示例演示了将行直接解包到三个变量中。__iter__ 方法通过提供顺序访问使其成为可能。

解包简洁,并且在您了解确切的列结构时效果很好。它对于小型、固定模式表特别有用。

将行转换为列表

可以使用 list 函数将迭代器转换为列表。

to_list.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    
    cursor.execute('''CREATE TABLE measurements
                     (timestamp TEXT, temp REAL, humidity REAL)''')
    cursor.execute("INSERT INTO measurements VALUES ('2025-01-01', 22.5, 45.0)")
    
    cursor.execute("SELECT * FROM measurements")
    row = cursor.fetchone()
    
    # Convert row to list
    values = list(row)
    print(f"Measurement at {values[0]}: {values[1]}°C, {values[2]}%")

list 函数消耗迭代器并创建一个包含所有行值的新列表。当您需要索引访问时,这非常有用。

转换为列表会创建数据的副本,这会消耗额外的内存,但允许对值进行多次传递。

与 zip() 一起使用

行迭代器与 Python 的 zip 函数配合良好。

zip_columns.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    
    cursor.execute('''CREATE TABLE employees
                     (id INTEGER, name TEXT, department TEXT)''')
    cursor.execute("INSERT INTO employees VALUES (1001, 'Bob', 'IT')")
    
    cursor.execute("SELECT * FROM employees")
    row = cursor.fetchone()
    
    # Combine column names with values
    columns = ['ID', 'Full Name', 'Dept']
    for col, val in zip(columns, row):
        print(f"{col}: {val}")

此示例使用 zip 将自定义列名称与行值配对。__iter__ 方法提供用于压缩的值。

当您需要创建数据的自定义视图或需要将行值与其他序列组合时,Zipping 非常强大。

多次行迭代

该方法也适用于处理来自查询的多行。

multi_row.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    
    cursor.execute('''CREATE TABLE cities
                     (name TEXT, population INTEGER, country TEXT)''')
    cities = [
        ('Tokyo', 37400068, 'Japan'),
        ('Delhi', 28514000, 'India'),
        ('Shanghai', 25582000, 'China')
    ]
    cursor.executemany("INSERT INTO cities VALUES (?, ?, ?)", cities)
    
    cursor.execute("SELECT * FROM cities ORDER BY population DESC")
    for row in cursor:
        # Iterate over each row's values
        name, pop, country = row
        print(f"{name} ({country}): {pop:,}")

此示例显示了对多行的迭代,每行本身都是可迭代的。我们将每一行解包为变量以进行格式化输出。

对于处理结果集,该模式简洁高效,尤其是对于已知的列结构。

与 enumerate() 结合使用

迭代器与 enumerate 配合良好,可以进行索引访问。

enumerate.py
import sqlite3

with sqlite3.connect(':memory:') as conn:
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    
    cursor.execute('''CREATE TABLE inventory
                     (item TEXT, quantity INTEGER, price REAL)''')
    cursor.execute("INSERT INTO inventory VALUES ('Widget', 100, 9.99)")
    
    cursor.execute("SELECT * FROM inventory")
    row = cursor.fetchone()
    
    # Get column positions and values
    for idx, value in enumerate(row):
        col_name = row.keys()[idx]
        print(f"Column {idx} ({col_name}): {value}")

在这里,我们使用 enumerate 来获取每列的索引和值。然后,我们使用索引查找列名。

当您在处理期间需要位置信息和值时,此技术非常有用。

性能注意事项

__iter__ 方法有一些需要考虑的性能影响。

performance.py
import sqlite3
import time

with sqlite3.connect(':memory:') as conn:
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    
    # Create large table
    cursor.execute('''CREATE TABLE big_data (id INTEGER, value TEXT)''')
    cursor.executemany("INSERT INTO big_data VALUES (?, ?)",
                     ((i, str(i)*10) for i in range(100000)))
    
    # Time iteration approaches
    start = time.time()
    cursor.execute("SELECT * FROM big_data")
    for row in cursor:
        list(row)  # Force full iteration
    print(f"Iteration time: {time.time() - start:.3f}s")

此基准测试表明,行迭代通常很快,但转换为列表或其他结构会增加开销。对于大型数据集,请考虑直接列访问。

__iter__ 方法本身已优化,但使用方式会影响性能。分析您的特定用例。

最佳实践

资料来源

作者

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

列出所有 Python 教程