News for hackers. Stuff that matters.
Re:Lesser known parts of Python standard library – Trickster... by sevensor on Thursday September 05, 2024 @08:55AM (#41456186)
I mostly migrated to frozen dataclasses from namedtuples when dataclasses became available. I’m curious about your preference for the namedtuple. Is it the lighter weight, the strong immutability, the easy destructing? Or is it that most tuples might as well be namedtuples? Those are the advantages I can think of anyway :)
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.
Re:Lesser known parts of Python standard library – Trickster... by est on Thursday September 05, 2024 @10:54AM (#41457224)
If I find my self write a[0] a[1] a[2] in more than one place, I would upgrade it to a namedtuple. Much better readability, can be defined inline like `MyTuple = namedtuple('MyTuple', 'k1 k2 k3')`
Re:Lesser known parts of Python standard library – Trickster... by gcr on Thursday September 05, 2024 @11:53AM (#41457793)
Any reason not to consider pydantic as the next step?
Re:Lesser known parts of Python standard library – Trickster... by JimDabell on Thursday September 05, 2024 @01:32PM (#41458776)
Every time I’ve used Pydantic I’ve found it to be a tonne of friction. The developer ergonomics just don’t seem right.

These days I use attrs and cattrs, and I’m much happier. Everything feels a lot more straightforward.

attrs is what Python’s dataclasses were based on, but they kept on improving it, so attrs just feels like standard Python with a little bit extra.