Description
This works fine:
def __add__(self, other: object) -> 'Currency':
if isinstance(other, self.__class__) and isinstance(other, Currency):
return self.__class__(other.amt + self.amt)
return NotImplemented
but this does not:
def __add__(self, other: object) -> 'Currency':
if isinstance(other, Currency) and isinstance(other, self.__class__): # only expression order is flipped
return self.__class__(other.amt + self.amt)
return NotImplemented
throws: error: "object" has no attribute "amt"
Full code to reproduce it locally: https://gist.github.com/pirate/b3ef5a25449285dadc366dd926cebcea
The intention is to check that other
is the same class as self
(to prevent adding BTC
to USD
by accident). That check alone should imply that other
is a subclass of Currency
(since the __add__
method is defined on Currency
), but it looks like I have to explicitly make both assertions, and make the Currency
assertion after the self.__class__
one in order for mypy to narrow the type correctly.
Correct me if I'm mistaken, but I think there may be two bugs here:
- The order of
isinstance
checks shouldn't matter (especially not in anand
expression) - The
isinstance(other, Currency)
should not even be necessary, as it's implied that other is aCurrency
ifother.__class__ == self.__class__
This issue discusses a vaguely similar type-narrowing problem, but I'm not sure if it's actually related: #2776