PEP 661 – Sentinel Values, accepted 5 years later

16 points by azhenley


natfu

That's interesting, I wonder how the semantics of some packages will change. For example,

NOT_FOUND = sentinel("NOT_FOUND")
def get_item(iid: str) -> Item | NOT_FOUND: ...

instead of returning Item | None.

Of course, you could imagine multiple sentinels to carry additional meaning; you could always do this but there was no "blessed" approach in the docs. Maybe this will steer package writers in a different direction?

MISSING_ID = sentinel("MISSING_ID")
MISSING_VALUE = sentinel("MISSING_VALUE")

def get_item(iid: str) -> Item | MISSING_ID | MISSING_VALUE: ...

This is a bit contrived but in this case, I can differentiate between an existing ID with no attached value and a miss because there's no such ID.

The "pythonic" way would probably mean using exceptions where I see this as a more functional approach to how I would usually write Python.

isuffix

For the case of default values on named arguments, I find that with the simple addition of the auto value (alongside none) in Typst, I can represent pretty much any named argument interface I want.

The problem with none alone is that it doesn't really make sense as a default for most named arguments. none is great for a default return value, but as an argument passed into a function it often doesn't carry the correct meaning as a noun: does matrix(axes=None) mean to remove the axes or keep them as normal? Does passing none differ from not passing anything at all? And if you take the multiple dispatch approach to distinguish including the parameter or not, then you've lost any central location to document the behavior of the parameter. auto gives you a great default value that literally means to do the right thing with the information you have.

auto also pairs well with none as the signature auto | none can act like a more explicit boolean, and the signature T | auto | none tells you a lot about how the function is going to use the value, e.g. if T is color, then auto would likely choose a default like white or black or inherit from a parent, T would set the color explicitly, and none would either avoid setting a color at all or use transparent based on the context.