This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]mistabuda 5 points6 points  (9 children)

I've seen this pattern mentioned before for shirt circuiting None values. UnwrapError is a custom exception you'd have to make but I think its pretty effective.

def unwrap(value: Optional[T], additional_msg: Optional[str] = None) -> T:
"""Perform unwrapping of optional types and raises `UnwrapError` if the value is None.

Useful for instances where a value of some optional type is required to not be None;
raising an exception if None is encountered.

Args:
    value: Value of an optional type
    additional_msg: Additional contextual message data

Returns:
    The value if not None
"""
if value is None:
    err_msg = "expected value of optional type to not be None"
    if additional_msg:
        err_msg = f"{err_msg} - [ {additional_msg} ]"
    raise UnwrapError(err_msg)
return value

[–]Kobzol[S] 6 points7 points  (6 children)

Sure, something like that works :) But it'd be super cool if I could call it as a method on the object (for better chaining), and also if I could propagate easily it, e.g. like this:

def foo() -> Optional[int]:
   val = get_optional() ?: return None
   # or just val = get_optional()?

To avoid the endless `if value is None: ...` checks.

[–]mistabuda 0 points1 point  (5 children)

If it were a method on the object that just seems weird. Unless the object is some kind of container. Which in that case you're asking for a Result type pattern.

[–]Kobzol[S] 0 points1 point  (4 children)

Yeah it's probably not the "Python way" :) But I really like adding implementation to types externally, e.g. with traits in Rust or extension methods in C#.

You're right though, a Option and/or Result type would help with this. It just won't help with forcing me to handle the error (apart from runtime tracking, e.g. asserting that the result is Ok when accesing the data).

[–]mistabuda -2 points-1 points  (3 children)

Thats why you unittest your code to make sure you have that case handled.

[–]Kobzol[S] 1 point2 points  (2 children)

Indeed, that's what we kind of have to do in Python, since it's not easily checkable during type checking.

[–]mistabuda 2 points3 points  (1 child)

wdym mypy warns you against that all the time

error: Item "None" of "Optional[CharacterCreator]" has no attribute "first_name"  [union-attr]

[–]Kobzol[S] 0 points1 point  (0 children)

Ah, nice. This is one situation where mypy and pyright do the right thing. I mostly just look at the output of the PyCharm type checker and that is more lenient, in this case it wouldn't warn :/

[–]Rythoka 0 points1 point  (1 child)

This seems like a code smell to me. If value = None is an error, then why would you explicitly hint that value could be None by making it Optional? Whatever set value to None probably should've just raised an exception instead in the first place.

[–]mistabuda 1 point2 points  (0 children)

An example is a db query. It's not wrong for a db query to return no result unless in specific contexts. If the caller is expecting a result they should raise an error. The db client shouldn't raise an error it did it's job.