logoalt Hacker News

Much Ado About None: Sentinel Values in Python

67 points • by sebg • last Thursday at 10:24 PM • 45 comments • view on HN

Comments

pwdisswordfishq • yesterday at 9:01 PM

So much trouble to avoid introducing the optional monad.

➕ show 3 replies
RantyDave • yesterday at 8:16 PM

"A simple cache returns None both for a missing key and for a key that maps to None."

No, it returns KeyError. Or at least it should.

➕ show 4 replies
lpghatguy • yesterday at 8:31 PM

When I was writing a bunch of Lua, I was a big fan of having a None sentinel value (Lua uses 'nil' for representing absence) and it was useful for a lot of things similar to Pydantic's MISSING.

This distinction is something that I think is actually handy about JavaScript, and distinguishing between 'null' and 'undefined' is sometimes useful for similar reasons.

➕ show 1 reply
chowells • yesterday at 8:07 PM

I like it. I can't see how to do better while remaining compatible with Python idioms.

➕ show 1 reply
throwaway2037 • yesterday at 11:18 PM

Here is the sample code from the article:

    > MISSING = sentinel("MISSING")

    > def update_email(user_id: int, email: str | None | MISSING = MISSING) -> None:
    >     if email is MISSING:
    >         return  # nothing to update
    >     elif email is None:
    >         db.delete_email(user_id)
    >     else:
    >         db.set_email(user_id, email.lower())  # narrowed to str
I see this style frequently from long time Python programmers. The language is so dynamic that people begin to think this is a good way to program. Hot take: It is not. Why not two different functions called delete_email() and set_email()? That would be more clear.
➕ show 1 reply
est • today at 1:14 AM

I just return a customized Exception type. Works about the same.

shepherdjerred • today at 4:15 AM

I hate sentinel values. Even/especially with AI-generated code.

1. If your date does not have a value, do not return 0, an empty string, or None. Use a discriminated union and model your domain rigorously.

2. If your data model accepts None/undefined as a value, that should translate to your business model as well. For example

3. Do not make your `name` field as `string | undefined` just because there might be an intermediate loading or processing state. It's better to model that as something like `Loaded<string>` where Loaded is something like a Result or Optional type (though ideally more rigorously defined)

Here is what I've done for years in TypeScript, though now in a nice package thanks for AI: https://github.com/shepherdjerred/monorepo/blob/main/package...

jMyles • today at 1:36 AM

I have a library that's approximately half joking that I use for (sentinel and other) special value constants. If you like reading test suites, this one will get ya:

https://github.com/nucypher/constantSorrow/blob/master/tests...