[Python-ideas] Null coalescing operators

Trent Nelson trent at snakebite.org
Fri Sep 18 20:21:39 CEST 2015


On Fri, Sep 18, 2015 at 10:42:59AM -0700, Mark Haase wrote:
> StackOverflow has many questions
> <http://stackoverflow.com/search?q=%5Bpython%5D+null+coalesce> on the
> topic of null coalescing operators in Python, but I can't find any
> discussions of them on this list or in any of the PEPs. Has the
> addition of null coalescing operators into Python ever been discussed
> publicly?
> 
> Python has an "or" operator that can be used to coalesce false-y
> values, but it does not have an operator to coalesce "None"
> exclusively.

Hmmm, I use this NullObject class when I want to do stuff similar to what
you've described:

class NullObject(object):
    """
    This is a helper class that does its best to pretend to be forgivingly
    null-like.
    >>> n = NullObject()
    >>> n
    None
    >>> n.foo
    None
    >>> n.foo.bar.moo
    None
    >>> n.foo().bar.moo(True).cat().hello(False, abc=123)
    None
    >>> n.hornet(afterburner=True).shotdown(by=n().tomcat)
    None
    >>> n or 1
    1
    >>> str(n)
    ''
    >>> int(n)
    0
    >>> len(n)
    0
    """
    def __getattr__(self, name):
        return self

    def __getitem__(self, item):
        return self

    def __call__(self, *args, **kwds):
        return self

    def __nonzero__(self):
        return False

    def __repr__(self):
        return repr(None)

    def __str__(self):
        return ''

    def __int__(self):
        return 0

    def __len__(self):
        return 0

Source: https://github.com/tpn/tpn/blob/master/lib/tpn/util.py#L1031

Sample use: https://github.com/enversion/enversion/blob/master/lib/evn/change.py#L1300

    class ChangeSet(AbstractChangeSet):
        @property
        def top(self):
            """
            Iff one child change is present, return it.
            Otherwise, return an instance of a NullObject.
            """
            if self.child_count != 1:
                return NullObject()
            else:
                top = None
                for child in self:
                    top = child
                    break
                return top

        @property
        def is_tag_create(self):
            return self.top.is_tag_create

        @property
        def is_tag_remove(self):
            return self.top.is_tag_remove

        @property
        def is_branch_create(self):
            return self.top.is_branch_create

        @property
        def is_branch_remove(self):
            return self.top.is_branch_remove

Having self.top potentially return a NullObject simplifies the code for
the four following properties.

> I can implement this behavior myself in pure Python, but it would be
> (a) nice to have it the in the standard library, and (b) even nicer to
> have an operator in the language, since terseness is the goal.
> 

> As a motivating example: when writing web services, I often want to
> change the representation of a non-None value but also need to handle
> None gracefully. I write code like this frequently: 
> 
>     response = json.dumps({ 'created': created.isoformat() if created
>     is not None else None, 'updated': updated.isoformat() if updated
>     is not None else None, ...  })
> 
> With a null-aware member access operator, I could write this instead:
> 
>     response = json.dumps({ 'created': created?.isoformat(),
>     'updated': updated?.isoformat(), ...  })

If you can alter the part that creates `created` or `updated` to return
a NullObject() instead of None when applicable, you could call
`created.isoformat()` with out the addition clause.

> Thanks, Mark

    Trent.


More information about the Python-ideas mailing list