Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does mypy not consider "bool(object) == True"?

If Python classes do not define __bool__ or __len__, bool(<class object>) defaults to True.

However, mypy (tested with: v1.15.0) doesn't seem to consider this.

class A:
    def __init__(self) -> None:
        self._value = 42

    def foobar(self) -> int:
        return self._value


def foobar(a: A | None) -> int | None:
    # case: `a is None` ⇒ returns `None`
    # case: `a is not None` ⇒ returns `42`
    # however: mypy complains...
    #   `Incompatible return value type (got A | int | None), expected "int | None"`
    return a and a.foobar()

To my understanding, the expression a and a.foobar() can only evaluate to type A if a is not None and bool(a) == False, which cannot happen. My conclusion is that mypy doesn't consider that a is not Nonebool(a) == True.

Am I right that mypy simply fails on this? Is there any convenient workaround to write optional_obj and optional_obj.attribute in a mypy-compatible way?

like image 675
matheburg Avatar asked Dec 03 '25 21:12

matheburg


2 Answers

You fail to consider subclasses:

(playground)

class B(A):
    def __bool__(self) -> bool:
        return False

reveal_type(foobar(B()))  # `int | None` at type checking time,
                          # but `B` at runtime.

To avoid this pitfall, mark A as @final:

(playground)

from typing import final

@final
class A: ...

As for a better way to write optional_obj and optional_obj.attribute, see How do I get Pylance to ignore the possibility of None?.

like image 195
InSync Avatar answered Dec 05 '25 11:12

InSync


Is there any convenient workaround to write optional_obj and optional_obj.attribute in a mypy-compatible way?

Possibly you are trying to be too clever. This is not 100% equivalent to your original expression, but it might be what you actually meant:

optional_obj.attribute if optional_obj is not None else None
like image 28
John Bollinger Avatar answered Dec 05 '25 10:12

John Bollinger



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!