Most active commenters
  • stfwn(3)

←back to thread

317 points est | 11 comments | | HN request time: 0.861s | source | bottom
Show context
oooooof ◴[] No.17448560[source]
What is it? The link points to a discussion more deep than I’m willing to read.
replies(10): >>17448567 #>>17448570 #>>17448571 #>>17448572 #>>17448575 #>>17448579 #>>17448584 #>>17448591 #>>17448617 #>>17448638 #
est ◴[] No.17448572[source]
It's a controversial PEP https://www.python.org/dev/peps/pep-0572/ which allows you to write Python like this:

    def foo():
        if n := randint(0, 3):
            return n ** 2
        return 1337


    [(x, y, x/y) for x in input_data if (y := f(x)) > 0]
replies(7): >>17448580 #>>17448633 #>>17448694 #>>17448731 #>>17448946 #>>17449000 #>>17449023 #
1. stfwn ◴[] No.17448946[source]
This immediately looks useful for things like:

    if foo := bar[baz]:
        bar[baz] += 1
        return foo
    else:
        bar[baz] = 1
        return 0
Where foo is a dict keeping track of multiple things, and a non-existing key (baz) is never an error but rather the start of a new count. Faster and more readable than

    if baz in list(bar.keys()):
    ....
Similar to Swift’s ‘if let’, it seems.
replies(4): >>17448968 #>>17449008 #>>17449051 #>>17449074 #
2. kelnos ◴[] No.17448968[source]
For stuff like that I'd just use `defaultdict`. That if/else tree then reduces to 2 lines total.
replies(1): >>17448988 #
3. stfwn ◴[] No.17448988[source]
That’s a good tip, thanks!
4. antoinealb ◴[] No.17449008[source]
As pointed, you can use either a default dict or just simply, and [more pythonic](https://blogs.msdn.microsoft.com/pythonengineering/2016/06/2...):

    try:
      bar[baz] += 1
    except KeyError:
      bar[baz] = 1
Also you can check if a key is in a dict simply by doing "if baz in bar" no need for "list(bar.keys())", which will be slow (temp object + linear scan) vs O(1) hashmap lookup.
replies(3): >>17449075 #>>17449181 #>>17449409 #
5. sametmax ◴[] No.17449051[source]
Don't wait for 3.8, and don't bother with defaultdict.

collections.Counter is what you want for the counting case.

dict.get() + dict.setdefault() for the general case.

defaultdict is only useful if the factory is expensive to call.

6. eesmith ◴[] No.17449074[source]
The place I see using it is in (quoting Python's "python.exe-gdb.py"):

        m = re.match(r'\s*(\d+)\s*', args)
        if m:
            start = int(m.group(0))
            end = start + 10

        m = re.match(r'\s*(\d+)\s*,\s*(\d+)\s*', args)
        if m:
            start, end = map(int, m.groups())
With the new syntax this becomes:

        if m := re.match(r'\s*(\d+)\s*', args):
            start = int(m.group(0))
            end = start + 10

        if m := re.match(r'\s*(\d+)\s*,\s*(\d+)\s*', args)
            start, end = map(int, m.groups())
This pattern occurs just often enough to be a nuisance. For another example drawn from the standard library, here's modified code from "platform.py"

    # Parse the first line
    if (m := _lsb_release_version.match(firstline)) is not None:
        # LSB format: "distro release x.x (codename)"
        return tuple(m.groups())

    # Pre-LSB format: "distro x.x (codename)"
    if (m := _release_version.match(firstline)) is not None:
        return tuple(m.groups())

    # Unknown format... take the first two words
    if l := firstline.strip().split():
        version = l[0]
        if len(l) > 1:
            id = l[1]
replies(1): >>17454726 #
7. stfwn ◴[] No.17449075[source]
The error-catching method seemed too drastic to me before, but the article explains the LBYL vs. EAFP arugument quite well. Thanks!

I should find a way to get more code reviews, I really enjoy learning these small nuggets of info.

8. bb88 ◴[] No.17449181[source]
It's also time saving since the hash lookup needs to be done at most 1, as well. GP has two lookups in the hash list.
9. bocklund ◴[] No.17449409[source]
Alternatively

`bar[baz] = bar.get(baz, 0) + 1`

One line and no error checking.

But the OP was probably just illustrating a basic example where you might have some more intense logic

10. est ◴[] No.17454726[source]
It' a problem with re module really.

re.match should return a match object no matter what, and .group() should return strings, empty string if non were matched.

replies(1): >>17455316 #
11. eesmith ◴[] No.17455316{3}[source]
I don't see how that would improve things. Could you sketch a solution based around your ideas?