The problem that I am having is distributed over many source files and my attempts to reproduce the problem in a simple linear format have failed. Nonetheless the problem I am having is simply described.
I have a class Path for which I implement __hash__ and __eq__
I have an item of type Path in a dict as evidenced by
path in list(thedict) >> True I verify that path == other and hash(path) == hash(other) and id(path) == id(other) where other is an item taken straight out of list(thedict.keys()). Yet, I get the following
path in thedict: >> False and attempting the following results in a KeyError
thedict[path] So my question is, under what circumstance is this possible? I would have expected that if the path is in list(thedict) then it must be in thedict.keys() and hence we must be able to write thedict[path]. What is wrong with this assumption?
Further Info
If it helps, the classes in question are listed below. It is at the level of SpecificationPath that the above issue is observed
class Path: pass @dataclass class ConfigurationPath(Path): configurationName: str = None def __repr__(self) -> str: return self.configurationName def __hash__(self): return hash(self.configurationName) def __eq__(self, other): if not isinstance(other, ConfigurationPath): return False return self.configurationName == other.configurationName #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @dataclass class SpecificationPath(Path): configurationPath: ConfigurationPath specificationName: str = None def __repr__(self) -> str: return f"{self.configurationPath}.{self.specificationName or ''}" def __hash__(self): return hash((self.configurationPath, self.specificationName)) def __eq__(self, other): if not isinstance(other, SpecificationPath): return False if self.configurationPath != other.configurationPath: return False if self.specificationName != other.specificationName: return False return True In response to a comment below, here is the output in the (Spyder) debug terminal, where pf is an object containing the paths dictionary using paths as keys and the object in question (self) has the path.
In : others = list(pf.paths.keys()) In : other = others[1] In : self.path is other Out[1]: True In : self.path in pf.paths Out[1]: False
isinstancecheck fails, you should be returningNotImplemented, notFalse; that will allow the right-side class (if it's not the same as the left) to attempt the comparison (if both returnNotImplemented, Python converts that toFalsefor you).__eq__and__hash__?@dataclasswould generate the__eq__for you with no changes; make it@dataclass(frozen=True)would generate the__hash__for you too (@dataclass(unsafe_hash=True)would do it too, but leave your instances mutable, which hashable instances should not be).