1

I am trying to create a SimpleNamespace with false value, but it is not working for me.

EMPTY = types.SimpleNamespace(__bool__=lambda self: False)
assert bool(EMPTY) == False  # raises error!!

Is there a way to create SimpleNamespace with boolean value false?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
gustavodiazjaimes
  • 2,441
  • 1
  • 19
  • 14
  • 4
    If this can be done at all, it would require subclassing `SimpleNamespace` and adding the `__bool__()` method there. Special methods are generally not looked for in the instance itself, as you're trying to do here, but only in the class. – jasonharper Feb 16 '22 at 17:58

2 Answers2

1

It is not possible to give custom, "real" methods to individual instances of a class. In the original code, EMPTY.__bool__ is not a method, but an ordinary function. You can see this by trying to invoke it explicitly:

>>> EMPTY = types.SimpleNamespace(__bool__=lambda self: False)
>>> EMPTY.__bool__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: <lambda>() missing 1 required positional argument: 'self'

See also Adding a Method to an Existing Object Instance. While it's possible - following the advice there - to make EMPTY.__bool__ behave like a method:

>>> EMPTY = types.SimpleNamespace()
>>> EMPTY.__bool__ = types.MethodType(lambda self: False, EMPTY)
>>> EMPTY.__bool__()
False

that will still be ignored by bool:

>>> bool(EMPTY)
True

The implementation of bool looks up __bool__ directly on the class, because it has no reason to expect an instance to have such an attribute.

Instead, we need to have our own class, with an actual method named __bool__ that does the right thing. Thus:

class PossiblyEmptyNamespace(types.SimpleNamespace):
    """A namespace that is falsey when it doesn't contain anything."""
    def __bool__(self):
        return bool(vars(self))

Now we can test that:

>>> EMPTY = PossiblyEmptyNamespace()
>>> bool(EMPTY)
False
>>> EMPTY.foo = 'bar'
>>> bool(EMPTY) # oops, not actually empty any more.
True
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
0

As mentioned in the comments, you'll need to make a subclass. Dunder methods like __bool__ are generally looked up on the class, not the specific instance, so setting a field on an instance will do you no good in this case.

from types import SimpleNamespace

class FalsyNamespace(SimpleNamespace):
    def __bool__(self):
        return False

EMPTY = FalsyNamespace()
assert bool(EMPTY) == False
Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116