Skip to content

Inheritance + if/elif/else chain of isinstance() doesn't constrain type as expected #4864

Description

@osandov

I have something like the following code:

from typing import Any, Union


class A:
    pass


class B(A):
    def __init__(self):
        self.member = 1


class C(A):
    def __init__(self):
        self.member = 2


def f(obj: A) -> int:
    if isinstance(obj, B):
        pass
    elif isinstance(obj, C):
        pass
    else:
        raise ValueError()
    return obj.member

mypy claims:

test.py:25: error: "A" has no attribute "member"

However, at line 25, it's clear that obj must be either a B or a C. If I remove the elif isinstance(obj, C) branch, then there is no error.

This similar code has a related error:

from typing import Any, Union


class A:
    pass


class B(A):
    def __init__(self):
        self.member = 1


class C(A):
    def __init__(self):
        self.member = 2


def f(obj: A) -> Union[B, C]:
    if isinstance(obj, B):
        pass
    elif isinstance(obj, C):
        pass
    else:
        raise ValueError()
    return obj
test.py:25: error: Incompatible return value type (got "A", expected "Union[B, C]")

Interestingly, if I remove the inheritance so that B and C are no longer subclasses of A, there is no error.

This happens on mypy 0.570 and current git (0.590-dev-3346cfad75374c096b1dd8024df24ce50f18a35c).

Activity

  1. ilevkivskyi commented on Apr 6, 2018

    @ilevkivskyi
    Member

    It looks like another case of join vs union problem plus a complex binder situation. Why can't you just use obj: Union[B, C] in the signature of your function?

    I would say this is a relatively low priority. There may be some binder refactoring later, then this will probably be easier to fix.

  2. osandov commented on Apr 7, 2018

    @osandov
    Author
  3. hauntsaninja commented on Dec 27, 2025

    @hauntsaninja
    Collaborator

    This was fixed in #18538

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions