Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a falsy sentinel object in Python?

I have a function which is designed to be called by passing in one of two keyword arguments. I'm using a sentinel object as default value, so that I can make sure no one just calls func() without any arguments, which is a clear logical error. It is ok to call the function by passing None as a value for one of the arguments, in those cases it just doesn't do any processing.

NO_VALUE = object()


def func(*, arg1 = NO_VALUE, arg2 = NO_VALUE):
    if arg1 is NO_VALUE and arg2 is NO_VALUE:
        raise ValueError("Pass in one of `arg1` or arg2`.")

    if arg1 is not NO_VALUE and arg1:
        # Do something with a truthy `arg1` value.
    if arg2 is not NO_VALUE and arg2:
        # Do something with a truthy `arg2` value.

Could I somehow easily make NO_VALUE be falsy, so that I could simplify the if arg1 is not NO_VALUE and arg1 and if arg2 is not NO_VALUE and arg2 to just if arg1 and if arg2 respectively?

I tried making NO_VALUE an empty tuple () but it seems that the id() of an empty tuple is always(?) same as the id() of any other empty tuple. I also don't want to make NO_VALUE e.g. an empty list object, since then I'd get linter warnings about using a mutable default value.

like image 503
ruohola Avatar asked May 26 '26 12:05

ruohola


1 Answers

In any case: for a Python object to be "Falsy" it can be an instance of a class which implements __bool__ and returns False when that is called:

class FalsySentinel:
    def  __bool__(self):
        return False


NO_VALUE = FalsySentinel()


def func(*, arg1 = NO_VALUE, arg2 = NO_VALUE):
    if arg1 is NO_VALUE and arg2 is NO_VALUE:
        raise ValueError("Pass in one of `arg1` or arg2`.")

    if arg1:
        # Do something with a truthy `arg1` value.
    if arg2:
        # Do something with a truthy `arg2` value.

There are other ways to produce falsy objects, like objects that implement __len__ and return 0 on it - but this is the most explicit and straightforward way.

like image 107
jsbueno Avatar answered Jun 01 '26 07:06

jsbueno