CodeQL 文档

不一致的相等性和哈希

ID: py/equals-hash-mismatch
Kind: problem
Security severity: 
Severity: warning
Precision: very-high
Tags:
   - reliability
   - correctness
   - external/cwe/cwe-581
Query suites:
   - python-security-and-quality.qls

点击查看 CodeQL 仓库中的查询

为了符合对象模型,定义了自己的相等方法的类也应该定义自己的哈希方法,或者不可散列。如果未定义哈希方法,则使用超类的hash。这不太可能导致预期行为。

可以通过将类的__hash__属性设置为None来使其不可散列。

在 Python 3 中,如果您定义了类级别的相等方法而省略了__hash__方法,则该类会自动标记为不可散列。

建议

当您为类定义__eq__方法时,请记住实现__hash__方法或设置__hash__ = None

示例

在以下示例中,Point类定义了相等方法,但没有哈希方法。如果对该类调用 hash,则使用为object定义的哈希方法。这不太可能给出所需的行为。 PointUpdated类更好,因为它定义了相等方法和哈希方法。如果Point不用于dictset,则它可以定义为下面所示的UnhashablePoint

为了完全符合对象模型,该类还应该定义不等方法(由另一条规则识别)。

# Incorrect: equality method defined but class contains no hash method
class Point(object):

    def __init__(self, x, y):
        self._x = x
        self._y = y

    def __repr__(self):
        return 'Point(%r, %r)' % (self._x, self._y)

    def __eq__(self, other):
        if not isinstance(other, Point):
            return False
        return self._x == other._x and self._y == other._y


# Improved: equality and hash method defined (inequality method still missing)
class PointUpdated(object):

    def __init__(self, x, y):
        self._x = x
        self._y = y

    def __repr__(self):
        return 'Point(%r, %r)' % (self._x, self._y)

    def __eq__(self, other):
        if not isinstance(other, Point):
            return False
        return self._x == other._x and self._y == other._y

    def __hash__(self):  
        return hash(self._x) ^ hash(self._y)

# Improved: equality method defined and class instances made unhashable
class UnhashablePoint(object):

    def __init__(self, x, y):
        self._x = x
        self._y = y

    def __repr__(self):
        return 'Point(%r, %r)' % (self._x, self._y)

    def __eq__(self, other):
        if not isinstance(other, Point):
            return False
        return self._x == other._x and self._y == other._y

    #Tell the interpreter that instances of this class cannot be hashed
    __hash__ = None

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私