An Implementation of the Optional Object for Python
There is a difference between None as Empty and None as the result for an
Error. A common bad practice is to return None to indicate the absence of
something. Doing this introduces ambiguity into you code.
For example:
thing=stuff.getSomeThing().getAnotherThing()What will happen if the result from getSomeThing returns None? We will get an
AttributeError: 'NoneType' object has no attribute 'getAnotherThing'.
What can you do to prevent these kinds of exceptions? You can write defensively:
something=stuff.getSomeThing()
ifsomethingisnotNone:
thing=something.getAnotherThing()However, if we add to our chain, you can imagine how the nesting of defensive checks adds up quickly. These defensive checks obfuscate our actual business logic, decreasing readability. Furthermore, defensive checking is an error prone process, because it is easy to forget to check a required condition.
So we present you with an Optional object as an alternative.
Compatible with Python 3.10 and up!
pip install optional.pyYou can import it using:
fromoptionalimportNothing, Option, Optional, Something
You can set it to empty:
instead of: 🙀
returnNone
you can do: 😸
returnOptional.empty()
or
returnOptional.of()
You can set it to have content:
instead of: 🙀
return"thing"
you can do: 😸
returnOptional.of("thing")
You can check if its present:
instead of: 🙀
ifthingisnotNone:
you can do: 😸
thing=some_func_returning_an_optional() ifthing:
You can check if its empty:
instead of: 🙀
ifthingisNone:
you can do: 😸
thing=some_func_returning_an_optional() ifnotthing:
You can match against the result and destructure the value:
instead of: 🙀
print(thing)
you can do: 😼
matchsome_func_returning_an_optional(): caseSomething(thing): print(thing)
You can match against an empty optional, but can't destructure the value:
instead of: 😿
ifthingisNone: print(None) # very odd
you can do: 😼
matchsome_func_returning_an_optional() caseNothing(): print("We didn't get a thing!")
You can compare two optionals: 😸
Optional.empty() ==Optional.empty() # TrueOptional.of("thing") ==Optional.of("thing") # TrueOptional.of("thing") ==Optional.empty() # FalseOptional.of("thing") ==Optional.of("PANTS") # False
There is complete test coverage and they pass in all Python versions 3.10 and up.
First, install pdm using these instructions.
Then, install the requirements using:
pdm install -G devYou can run the tests (with coverage) using:
pdm run pytest