The comments in OP's question have a lot of great insight about the warning, proper fixes and best practices, most were unfortunately not mentioned by the current answers. So here it goes:
About the warning itself, OP says:
This doesn't make sense to me, because the access is made from within the class.
No, it is not. other can be any class, not necessarily A. So even if you only pass A instances as other, there's nothing in the code that indicates or enforces that.
Indication can be done with type hints, as explained by Gulzar's answer.
And there are some approaches for enforcing this:
- Force
other's type to be A (or a subclass): if not isinstance(other, A): return False. This is the arguably the preferred way, but it does defeat Python's duck-typing.
- If instead of a regular method
_equals() you're using one of the predefined "rich comparison" special methods such as __eq__(), __lt__(), __gt__(), you can return a special value to give a chance to other's class reflection method to handle the call: if not isinstance(other, A): return NotImplemented
- If you want to preserve duck-typing to allow unknown classes, and you're not using a private attribute such as
_data (otherwise you'll still get the warning), you could use a try-block to handle a missing attribute:
try:
return self.data == other.data
except AttributeError: # other has no .data
return False