3 ms·
The main thing I find myself using them for is `_make()`. From the canonical [0] example: import sqlite3 EmployeeRecord = namedtuple('EmployeeRecord',
by sgarland 2y ago
The main thing I find myself using them for is `_make()`. From the canonical [0] example:
import sqlite3
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
print(emp.name, emp.title)
You could of course accomplish the same with a dictionary comprehension, but I find this to be less noisy. Also, they have `_asdict()` should you want to have the contents as a dict.
[0]: https://docs.python.org/3/library/collections.html#collections.namedtuple https://docs.python.org/3/library/collections.html#collectio...
- gcr 2y agoHoly shit that’s really clever. Didn’t know about _make, thank you!
- sgarland 2y agoI didn’t either until I read docs tbf. It’s just kind of thrown in as an afterthought for the section, too.
- judicious 2y agoDictionary comprehensions can be very elegant. List and dictionary comprehensions are very powerful and expressive abstractions. In fact, while not good practice you can pretty much write all Python code inside comprehensions including stuff regarding mutation. This is valid(as in it will run, but highly unidiomatic) code: quicksort = lambda arr: [pivot:=arr[0], left:= [x for x in arr[1:] if x < pivot], right := [x for x in arr[1:] if x >= pivot], quicksort(left) + [pivot] + quicksort(right)][-1] if len(arr) > 1 else arr print(quicksort([1, 33, -4, -2, 110, 5, 88]))
- hansvm 2y agoSometimes mutations in comprehensions are very expressive. def scan(items, f, initial): x = initial return (x := f(x, y) for y in items) There are lots of other short ways to write `scan`, but I don't think any of them map so clearly to a naive definition of what it's supposed to do.
- judicious 2y agoThat's incredibly clever, generators are underrated. I once challenged my friend to do leetcode problems with only expressions. Here's levenshtein distance, however it's incredibly clunky. levenshtein_distance = lambda s1, s2: [matrix := [[0] * (len(s2) + 1) for _ in range(len(s1) + 1)], [ [ (matrix[i].__setitem__(j, min(matrix[i-1][j] + 1, matrix[i][j-1] + 1, matrix[i-1][j-1] + (0 if s1[i-1] == s2[j-1] else 1))), matrix[i][-1])[1] for j in range(1, len(s2) + 1) ] for i in range(1, len(s1) + 1) ], matrix[-1][-1]][-1]
- wodenokoto 2y agoI'm not quite sure how the fetchall() return type looks, but couldn't you just for name, age, title in cursor.fetchall(): print(name, age, title) Ofcourse you have to come up with different variable names, but it still seems more elegant to just unpack.
- Joker_vD 2y agoHonestly, the "proper" way should be passing something like this def namedtuple_factory(cursor, row): fields = [column[0] for column in cursor.description] cls = namedtuple("Row", fields) return cls._make(row) to the fetchall(), to automatically keep the names in sync with those in the SQL query string.
- ttyprintk 2y agoImplemented as conn.row_factory = sqlite3.Row
- sgarland 2y agoBy default, List[Tuple]]. You could do a list comp over the fetchall(), but at that point there’s already some magic happening, so why not make it explicit?
- kstrauser 2y agoYou don't need `_make()` with dataclasses, and you get `asdict()` as a stand-alone function so it doesn't clash with each class's namespace. Here's what your code might look like with them: import sqlite3 from dataclasses import asdict, dataclass @dataclass class EmployeeRecord: name: str age: int title: str department: str paygrade: str conn = sqlite3.connect("/companydata") cursor = conn.cursor() cursor.execute("SELECT name, age, title, department, paygrade FROM employees") for emp in (EmployeeRecord(*row) for row in cursor.fetchall()): print(emp.name, emp.title) print(asdict(emp))