@@ -1320,27 +1320,11 @@ Connection objects
1320
1320
a :class: `Cursor ` object and the raw row results as a :class: `tuple `,
1321
1321
and returns a custom object representing an SQLite row.
1322
1322
1323
- Example:
1324
-
1325
- .. doctest ::
1326
-
1327
- >>> def dict_factory (cursor , row ):
1328
- ... col_names = [col[0 ] for col in cursor.description]
1329
- ... return {key: value for key, value in zip (col_names, row)}
1330
- >>> con = sqlite3.connect(" :memory:" )
1331
- >>> con.row_factory = dict_factory
1332
- >>> for row in con.execute(" SELECT 1 AS a, 2 AS b" ):
1333
- ... print (row)
1334
- {'a': 1, 'b': 2}
1335
-
1336
1323
If returning a tuple doesn't suffice and you want name-based access to
1337
1324
columns, you should consider setting :attr: `row_factory ` to the
1338
- highly optimized :class: `sqlite3.Row ` type. :class: `Row ` provides both
1339
- index-based and case-insensitive name-based access to columns with almost no
1340
- memory overhead. It will probably be better than your own custom
1341
- dictionary-based approach or even a db_row based solution.
1325
+ highly optimized :class: `sqlite3.Row `
1342
1326
1343
- .. XXX what's a db_row-based solution?
1327
+ See :ref: ` sqlite3-row-factory-how-to ` for more details.
1344
1328
1345
1329
.. attribute :: text_factory
1346
1330
@@ -1611,6 +1595,8 @@ Row objects
1611
1595
1612
1596
Two row objects compare equal if have equal columns and equal members.
1613
1597
1598
+ See :ref: `sqlite3-row-factory-how-to ` for more details.
1599
+
1614
1600
.. method :: keys
1615
1601
1616
1602
Return a :class: `list ` of column names as :class: `strings <str> `.
@@ -1620,21 +1606,6 @@ Row objects
1620
1606
.. versionchanged :: 3.5
1621
1607
Added support of slicing.
1622
1608
1623
- Example:
1624
-
1625
- .. doctest ::
1626
-
1627
- >>> con = sqlite3.connect(" :memory:" )
1628
- >>> con.row_factory = sqlite3.Row
1629
- >>> res = con.execute(" SELECT 'Earth' AS name, 6378 AS radius" )
1630
- >>> row = res.fetchone()
1631
- >>> row.keys()
1632
- ['name', 'radius']
1633
- >>> row[0 ], row[" name" ] # Access by index and name.
1634
- ('Earth', 'Earth')
1635
- >>> row[" RADIUS" ] # Column names are case-insensitive.
1636
- 6378
1637
-
1638
1609
1639
1610
.. _sqlite3-blob-objects :
1640
1611
@@ -2358,6 +2329,84 @@ can be found in the `SQLite URI documentation`_.
2358
2329
.. _SQLite URI documentation : https://www.sqlite.org/uri.html
2359
2330
2360
2331
2332
+ .. _sqlite3-row-factory-how-to :
2333
+
2334
+ How to work with row factories
2335
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2336
+
2337
+ By default, :mod: `!sqlite3 ` represent fetched rows as :class: `tuples <tuple> `.
2338
+ If a :class: `!tuple ` does not suit your needs,
2339
+ use the built-in :class: `Row ` type or a custom :attr: `~Connection.row_factory `.
2340
+ The former provides both indexed and case-insensitive named access to columns,
2341
+ with low memory overhead and minimal performance impact.
2342
+ Example use:
2343
+
2344
+ .. doctest ::
2345
+
2346
+ >>> con = sqlite3.connect(" :memory:" )
2347
+ >>> con.row_factory = sqlite3.Row
2348
+ >>> res = con.execute(" SELECT 'Earth' AS name, 6378 AS radius" )
2349
+ >>> row = res.fetchone()
2350
+ >>> row.keys()
2351
+ ['name', 'radius']
2352
+ >>> row[0 ], row[" name" ] # Access by index and name.
2353
+ ('Earth', 'Earth')
2354
+ >>> row[" RADIUS" ] # Column names are case-insensitive.
2355
+ 6378
2356
+
2357
+ If you need more flexibility, you can design your own row factory.
2358
+ Here's an example of a :class: `dict ` row factory:
2359
+
2360
+ .. doctest ::
2361
+
2362
+ >>> def dict_factory (cursor , row ):
2363
+ ... col_names = [col[0 ] for col in cursor.description]
2364
+ ... return {key: value for key, value in zip (col_names, row)}
2365
+
2366
+ >>> con = sqlite3.connect(" :memory:" )
2367
+ >>> con.row_factory = dict_factory
2368
+ >>> for row in con.execute(" SELECT 1 AS a, 2 AS b" ):
2369
+ ... print (row)
2370
+ {'a': 1, 'b': 2}
2371
+
2372
+ Here's an example of a optimised :class: `~collections.namedtuple ` factory:
2373
+
2374
+ .. testcode ::
2375
+
2376
+ from collections import namedtuple
2377
+ from functools import lru_cache
2378
+
2379
+ def _fields(cursor):
2380
+ return [col[0] for col in cursor.description]
2381
+
2382
+ @lru_cache
2383
+ def _make_cls(fields):
2384
+ return namedtuple("Row", fields)
2385
+
2386
+ def NamedTupleFactory(cursor, row):
2387
+ cls = _make_cls(_fields(cursor))
2388
+ return cls._make(row)
2389
+
2390
+ Example use:
2391
+
2392
+ .. doctest ::
2393
+
2394
+ >>> con = sqlite3.connect(" :memory:" )
2395
+ >>> con.row_factory = NamedTupleRow
2396
+ >>> cur = con.execute(" SELECT 1 AS a, 2 AS b" )
2397
+ >>> row = cur.fetchone()
2398
+ >>> row
2399
+ Row(a='1', b='2')
2400
+ >>> row[0 ] # Indexed access.
2401
+ 1
2402
+ >>> row.b # Attribute access.
2403
+ 2
2404
+
2405
+ With some adjustments, the above recipe can be adapted to use a
2406
+ :class: `~dataclasses.dataclass `, or any other custom class,
2407
+ instead of a :class: `~collections.namedtuple `.
2408
+
2409
+
2361
2410
.. _sqlite3-explanation :
2362
2411
2363
2412
Explanation
0 commit comments