I proposed a very toy example of a coalescing class that would solve the problem solved by brand new syntax in PEP 505. In my 5 minute version, there were several faults or limitations. For one, the class I wrote was misnamed, since it wasn't really about None-coalescing, but rather about exception-free nested access.
I've written a more robust version at https://pypi.org/project/coalescing/. I encourage issues or contributions at https://github.com/DavidMertz/coalesce. Mind you, this is still a few-hour-of-effort version, not rigorously tested. I want to thank Antoine Pitrou for proposing using Graham Dumpleton's warpt.ObjectProxy (which is truly magic). In almost no lines, I think I have something perhaps even better than PyMaybe. In particular, most of the time, there is no need to do an explicit `.unbox()` call... but at the suggestion of several people, I changed my first API to optionally pass a default value other than None within that method, if desired. I even made laziness in getting that value the default (but switchable) behavior. Dumpleton's magic means that boxed values can do pretty much anything the raw values can, so can generally ignore the .unbox() call at the end. Perhaps most magic of all, you can even ASSIGN into proxied values and that gets written to the original value (not shown in the doctests below). This adds something powerful that PEP 505 is completely unable to do. I believe that I have captured ALL the semantics of PEP 505 with no changes to Python syntax... and in a way that reads FAR better than all those new operators do. Access messy nested data structures GreedyAccess will keep marching down trees even if failure occurred earlier: >>> from coalesce import GreedyAccess, make_test >>> cfg = make_test() >>> GreedyAccess(cfg).user.profile.song <GreedyAccess proxy for 'Nightclubbing'> >>> GreedyAccess(cfg).user.profile.song + ' and spam' 'Nightclubbing and spam' >>> GreedyAccess(cfg).user.profile.food <GreedyAccess proxy for None> >>> print(GreedyAccess(cfg).user.profile.food.unbox()) None >>> GreedyAccess(cfg).user.profile.food.unbox('spam') 'spam' >>> GreedyAccess(cfg).user.profile.food.unbox('spam') + ' and spam' 'spam and spam' NoneCoalesce only descends until a None is encountered. Accessing attributes or keys of None will still fail: >>> from coalesce import NoneCoalesce >>> NoneCoalesce(cfg).user.profile.song <NoneCoalesce proxy for 'Nightclubbing'> >>> NoneCoalesce(cfg).user.profile.song.unbox() 'Nightclubbing' >>> NoneCoalesce(cfg).user.profile.food Traceback (most recent call last): ... AttributeError: 'types.SimpleNamespace' object has no attribute 'food' >>> NoneCoalesce(cfg).user.profile <NoneCoalesce proxy for namespace(arms=2, song='Nightclubbing')> >>> val = None >>> print(NoneCoalesce(val).attr) None We provide for returning values other than None if some other default is more useful for your use case (a zero-argument lambda function would often be useful here): >>> def say_spam(): ... return "spam" ... >>> GreedyAccess(cfg).user.profile.food.unbox(say_spam) 'spam' >>> GreedyAccess(cfg).user.profile.food.unbox(say_spam, lazy=False) #doctest: +ELLIPSIS <function say_spam ...> -- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/