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.
>>> maybe("I'm a value") "I'm a value" >>> maybe(None); None
Both Something and Nothing implement 4 methods allowing you to test their real value: is_some, is_none, get and or_else
>>> maybe("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'
In addition, Something and Nothing implement the Python magic methods allowing you to treat them as dictionaries:
>>> nested_dict = maybe(nested_dict) >>> nested_dict['store']['name'] 'MyStore' >>> nested_dict['store']['address'] None >>> nested_dict['store']['address']['street'].or_else('No Address Specified') 'No Address Specified'
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()[0].url.domain except (TypeError, IndexError, KeyError, AttributeError): url = "planetpython.org"
With Maybe you could simply do:
url = maybe(rss).load_feeds()[0]['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 ''
With maybe:
def get_user_zipcode(): return maybe(request.user).address.zipcode.or_else('')
Copyright 2015 - Eran Kampf
- Free software: BSD license
- Documentation: https://pymaybe.readthedocs.org.
- Code is hosted on GitHub