Используя нестандартные методы execute()
, executemany()
и executetescript()
объекта Connection
, код можно написать более кратко, поскольку не нужно явно создавать (часто лишние) объекты Cursor
.
Объекты Cursor
создаются неявно и эти методы быстрого вызова возвращают объекты курсора. Таким образом, можно выполнить инструкцию SELECT
и выполнить итерацию напрямую, используя только один вызов объекта Connection
.
import sqlite3 persons = [ ("Hugo", "Boss"), ("Calvin", "Klein") ] con = sqlite3.connect(":memory:") # Создать таблицу con.execute("create table person(firstname, lastname)") # Заполнить таблицу con.executemany("insert into person(firstname, lastname) values (?, ?)", persons) # Распечатать содержимое таблицы for row in con.execute("select firstname, lastname from person"): print(row) print("I just deleted", con.execute("delete from person").rowcount, "rows") # close() не является ярлыком и не вызывается автоматически, # поэтому объект соединения должен быть закрыт вручную con.close()
Одной из полезных функций модуля sqlite3
является встроенный класс sqlite3.Row
, предназначенный для использования в качестве фабрики строк.
Строки, заключенные в этот класс, могут быть доступны как по индексу - как кортежи, так и по имени без учета регистра символов:
import sqlite3 con = sqlite3.connect(":memory:") con.row_factory = sqlite3.Row cur = con.cursor() cur.execute("select 'John' as name, 42 as age") for row in cur: assert row[0] == row["name"] assert row["name"] == row["nAmE"] assert row[1] == row["age"] assert row[1] == row["AgE"] con.close()
Можно создать собственную фабрику Cursor.row_factory
, которая возвращает каждую строку в виде словаря с именами столбцов, сопоставленными со значениями:
def dict_factory(cursor, row): fields = [column[0] for column in cursor.description] return {key: value for key, value in zip(fields, row)}
Используя его, запросы теперь возвращают словарь вместо кортежа:
>>> con = sqlite3.connect(":memory:") >>> con.row_factory = dict_factory >>> for row in con.execute("SELECT 1 AS a, 2 AS b"): print(row) # {'a': 1, 'b': 2}
Следующая фабрика строк возвращает именованный кортеж:
from collections import namedtuple def namedtuple_factory(cursor, row): fields = [column[0] for column in cursor.description] cls = namedtuple("Row", fields) return cls._make(row)
namedtuple_factory()
можно использовать следующим образом:
>>> con = sqlite3.connect(":memory:") >>> con.row_factory = namedtuple_factory >>> cur = con.execute("SELECT 1 AS a, 2 AS b") >>> row = cur.fetchone() >>> row # Row(a=1, b=2) >>> row[0] # Индексированный доступ. # 1 >>> row.b # Доступ к атрибутам. # 2
С некоторыми изменениями приведенный выше рецепт можно адаптировать для использования класса данных dataclasses.dataclass
или любого другого пользовательского класса.
Объекты соединения могут использоваться как контекстные менеджеры, которые автоматически фиксируют или откатывают транзакции. В случае исключения транзакция откатывается, в противном случае сделка совершается:
import sqlite3 con = sqlite3.connect(":memory:") con.execute("create table person (id integer primary key, firstname varchar unique)") # впоследствии `con.commit()` вызывается автоматически with con: con.execute("insert into person(firstname) values (?)", ("Joe",)) # `con.rollback()` вызывается после завершения блока `with` с исключением. # исключение все еще вызывается и должно быть перехвачено try: with con: con.execute("insert into person(firstname) values (?)", ("Joe",)) except sqlite3.IntegrityError: print("couldn't add Joe twice") # Объект соединения, используемый в качестве диспетчера контекста, # только фиксирует или откатывает транзакции, поэтому объект # соединения должен быть закрыт вручную con.close()