Skip to content

explicit x is None should narrow union candidates like isinstance(x, type(None)) #4520

Closed
@bwo

Description

@bwo
from typing import Optional, List  # noqa


def union_test1(x):
    # type: (Optional[List[int]]) -> Optional[int]
    if x is None:
        return x
    else:
        return len(x)


def union_test2(x):
    # type: (Optional[List[int]]) -> Optional[int]
    if isinstance(x, type(None)):
        return x
    else:
        return len(x)

union_test1 with default options gives the error Incompatible return value type (got "Optional[List[int]]", expected "Optional[int]") (with --strict-optional, it does not give this error). union_test2 typechecks just fine. This strikes me as highly counterintuitive; even though (as the docs say) None is a valid value for each type, if one of the above checks allows the typechecker to learn that x is None and therefore not a list, it's hard to see why the other doesn't.

Failing that, I would suggest at least a documentation change to point out both the gotcha embodied in union_test1 and the workaround in union_test2.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions