mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 10:48:32 +00:00
[pylint
] De-emphasize __hash__ = Parent.__hash__
(PLW1641
) (#18613)
Summary -- This PR updates the docs for PLW1641 to place less emphasis on the example of inheriting a parent class's `__hash__` implementation by both reducing the length of the example and warning that it may be unsound in general, as @AlexWaygood pointed out on Notion. Test plan -- Existing tests --------- Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
6051a118d1
commit
6cd0669475
1 changed files with 10 additions and 46 deletions
|
@ -16,10 +16,10 @@ use crate::checkers::ast::Checker;
|
|||
///
|
||||
/// ## Why is this bad?
|
||||
/// A class that implements `__eq__` but not `__hash__` will have its hash
|
||||
/// method implicitly set to `None`, regardless of if a super class defines
|
||||
/// `__hash__`. This will cause the class to be unhashable, will in turn
|
||||
/// cause issues when using the class as a key in a dictionary or a member
|
||||
/// of a set.
|
||||
/// method implicitly set to `None`, regardless of if a superclass defines
|
||||
/// `__hash__`. This will cause the class to be unhashable, which will in turn
|
||||
/// cause issues when using instances of the class as keys in a dictionary or
|
||||
/// members of a set.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
|
@ -46,52 +46,16 @@ use crate::checkers::ast::Checker;
|
|||
/// return hash(self.name)
|
||||
/// ```
|
||||
///
|
||||
/// This issue is particularly tricky with inheritance. Even if a parent class correctly implements
|
||||
/// both `__eq__` and `__hash__`, overriding `__eq__` in a child class without also implementing
|
||||
/// `__hash__` will make the child class unhashable:
|
||||
///
|
||||
/// ```python
|
||||
/// class Person:
|
||||
/// def __init__(self):
|
||||
/// self.name = "monty"
|
||||
///
|
||||
/// def __eq__(self, other):
|
||||
/// return isinstance(other, Person) and other.name == self.name
|
||||
///
|
||||
/// def __hash__(self):
|
||||
/// return hash(self.name)
|
||||
///
|
||||
///
|
||||
/// class Developer(Person):
|
||||
/// def __init__(self):
|
||||
/// super().__init__()
|
||||
/// self.language = "python"
|
||||
///
|
||||
/// def __eq__(self, other):
|
||||
/// return (
|
||||
/// super().__eq__(other)
|
||||
/// and isinstance(other, Developer)
|
||||
/// and self.language == other.language
|
||||
/// )
|
||||
///
|
||||
///
|
||||
/// hash(Developer()) # TypeError: unhashable type: 'Developer'
|
||||
/// ```
|
||||
///
|
||||
/// One way to fix this is to retain the implementation of `__hash__` from the parent class:
|
||||
/// In general, it is unsound to inherit a `__hash__` implementation from a parent class while
|
||||
/// overriding the `__eq__` implementation because the two must be kept in sync. However, an easy
|
||||
/// way to resolve this error in cases where it _is_ sound is to explicitly set `__hash__` to the
|
||||
/// parent class's implementation:
|
||||
///
|
||||
/// ```python
|
||||
/// class Developer(Person):
|
||||
/// def __init__(self):
|
||||
/// super().__init__()
|
||||
/// self.language = "python"
|
||||
/// def __init__(self): ...
|
||||
///
|
||||
/// def __eq__(self, other):
|
||||
/// return (
|
||||
/// super().__eq__(other)
|
||||
/// and isinstance(other, Developer)
|
||||
/// and self.language == other.language
|
||||
/// )
|
||||
/// def __eq__(self, other): ...
|
||||
///
|
||||
/// __hash__ = Person.__hash__
|
||||
/// ```
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue