News for hackers. Stuff that matters.
Re:Lesser known parts of Python standard library – Trickster... by sgarland on Thursday September 05, 2024 @09:28AM (#41456456)
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#collectio...

Re:Lesser known parts of Python standard library – Trickster... by judicious on Thursday September 05, 2024 @11:04AM (#41457315)
Dictionary 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]))

Re:Lesser known parts of Python standard library – Trickster... by hansvm on Thursday September 05, 2024 @02:29PM (#41459237)
Sometimes 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.
Re:Lesser known parts of Python standard library – Trickster... by judicious on Thursday September 05, 2024 @03:03PM (#41459529)
That'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]
Re:Lesser known parts of Python standard library – Trickster... by gcr on Thursday September 05, 2024 @11:53AM (#41457789)
Holy shit that’s really clever. Didn’t know about _make, thank you!
Re:Lesser known parts of Python standard library – Trickster... by sgarland on Friday September 06, 2024 @07:40AM (#41465203)
I didn’t either until I read docs tbf. It’s just kind of thrown in as an afterthought for the section, too.
Re:Lesser known parts of Python standard library – Trickster... by wodenokoto on Thursday September 05, 2024 @12:39PM (#41458284)
I'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.
Re:Lesser known parts of Python standard library – Trickster... by Joker_vD on Thursday September 05, 2024 @01:25PM (#41458703)
Honestly, 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.
Re:Lesser known parts of Python standard library – Trickster... by ttyprintk on Friday September 06, 2024 @07:11AM (#41465022)
Implemented as conn.row_factory = sqlite3.Row
Re:Lesser known parts of Python standard library – Trickster... by sgarland on Friday September 06, 2024 @07:44AM (#41465243)
By 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?
Re:Lesser known parts of Python standard library – Trickster... by kstrauser on Thursday September 05, 2024 @02:27PM (#41459219)
You 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))
Re:Lesser known parts of Python standard library – Trickster... by ttyprintk on Friday September 06, 2024 @07:10AM (#41465015)
For that, you might as well conn.row_factory = sqlite3.Row
Re:Lesser known parts of Python standard library – Trickster... by kstrauser on Friday September 06, 2024 @08:58AM (#41465754)
That would be a better option, as long as the goal isn’t to demonstrate how namedtuples or dataclasses work.