A Python implementation of the Maybe pattern.
pip install pymaybe
from pymaybe import maybe first_name = maybe(deep_hash)['account']['user_profile']['first_name'].or_else("<unknown>")
Maybe monad is a programming pattern that allows to treat None values that same way as non-none values. This is done by wrapping the value, which may or may not be None to, a wrapper class.
The implementation includes two classes: Maybe and Something. Something represents a value while Nothing represents a None value. There's also a method maybe which wraps a regular value and and returns Something or Nothing instance.
"I'm a value") "I'm a value" maybe(None); Nonemaybe(
Both Something and Nothing implement 4 methods allowing you to test their real value: is_some, is_none, get and or_else
"I'm a value").is_some() True maybe("I'm a value").is_none() False maybe(None).is_some() False maybe(None).is_none() True maybe("I'm a value").get() "I'm a value" maybe("I'm a value").or_else(lambda: "No value") "I'm a value" maybe(None).get() Traceback (most recent call last): ... Exception: No such element maybe(None).or_else(lambda: "value") 'value' maybe(None).or_else("value") 'value'maybe(
In addition, Something and Nothing implement the Python magic methods allowing you to treat them as dictionaries:
'store']['name'] 'MyStore' nested_dict['store']['address'] None nested_dict['store']['address']['street'].or_else('No Address Specified') 'No Address Specified'nested_dict = maybe(nested_dict) nested_dict[
All other method calls on Something are forwarded to its real value:
>>> maybe('VALUE').lower() 'value' >>> maybe(None).invalid().method().or_else('unknwon') 'unknwon'
The Maybe pattern helps you avoid nasty try..except blocks. Consider the following code:
try: url = rss.load_feeds().url.domain except (TypeError, IndexError, KeyError, AttributeError): url = "planetpython.org"
With Maybe you could simply do:
url = maybe(rss).load_feeds()['url'].domain.or_else("planetpython.org")
Getting the current logged in user's name. Without maybe:
def get_user_zipcode(): address = getattr(request.user, 'address', None) if address: return getattr(address, 'zipcode', '') return ''
def get_user_zipcode(): return maybe(request.user).address.zipcode.or_else('')
Option (Scala) <http://www.scala-lang.org/api/current/scala/Option.html>_
Maybe (Java) <https://github.com/npryce/maybe-java>_
Maybe pattern (Python recipe) <http://code.activestate.com/recipes/577248-maybe-pattern/>_
Data.Maybe (Haskell) <http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-Maybe.html>_
Maybe (Ruby) <https://github.com/bhb/maybe>_
Copyright 2015 -
Eran Kampf <http://www.developerzen.com>_