【问题标题】:Which operators to overload for Python set to function properly [duplicate]哪些运算符要重载以使 Python 设置为正常运行 [重复]
【发布时间】:2019-01-18 19:57:40
【问题描述】:

我正在编写一个简单的容器类,我想将其实例存储在set 中,并希望删除重复项。比如我可以用tuple作为容器来写:

in>  set([(1,2),(1,2)])
out> {(1,2)}

但如果我改为定义

class Point(object):

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

    def __ge__(self, other):
        if self.x > other.x:
            return True
        elif self.x == other.x:
            return self.y >= other.y
        else:
            return False

    def __le__(self, other):
        if self.x < other.x:
            return True
        elif self.x == other.x:
            return self.y <= other.y
        else:
            return False

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

然后尝试

set([Point(1,2), Point(1,2)])

我最终得到了一组 2 个对象而不是 1 个。我需要重载哪些运算符(或者还需要做什么)才能使 set 以可预测的方式运行?

谢谢。

【问题讨论】:

  • setdict 对象依赖于对象的 __hash____eq__ 方法。您正在继承默认散列,它本质上是按 identity 散列的。由于您的两个对象都是不同的,因此它们散列到单独的存储桶中。您希望您的 __hash____eq__ 保持一致。在这种情况下,它们不是。

标签: python python-2.7 set operator-overloading


【解决方案1】:

根据https://docs.python.org/2.7/library/stdtypes.html#set-types-set-frozenset

集合对象是不同的可散列对象的无序集合。

根据https://docs.python.org/2.7/glossary.html#term-hashable

如果一个对象的哈希值在其生命周期内永远不会改变(它需要__hash__() 方法),并且可以与其他对象进行比较(它需要__eq__()__cmp__() 方法),则它是可哈希的。

你有__eq__,所以你现在只需要__hash__。 (__ne__ 也应该实现,否则你会得到x == ynot (x != y) 不匹配的结果。)

class Point(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __eq__(self, other):
        if isinstance(other, Point):
            return self.x == other.x and self.y == other.y
        return NotImplemented

    def __ne__(self, other)
        if isinstance(other, Point):
            return not (self == other)
        return NotImplemented

    def __hash__(self):
        return hash((self.x, self.y))


print(set([Point(1,2), Point(1,2)]))

结果:

set([<__main__.Point object at 0x02F4F090>])

对于样式点,您可能还想实现__repr__,这样您的设置对象看起来不错。添加def __repr__(self): return "Point({}, {})".format(self.x, self.y),您的集合将显示为set([Point(1, 2)])

【讨论】:

  • 注意:改变可散列对象可能会导致严重的问题。
  • @Goyo 你能详细说明一下吗?如果哈希在对象的生命周期中发生变化,这假设集合、字典和其他依赖哈希的对象需要重新组装,对吗?
  • @gt6989b 将可变对象设为可散列通常是不好的,或者至少,对你将要放入 dict 和 set 对象的对象进行变异。
  • 我想知道为什么__repr__ 还不够。我试过但 set 无法删除重复的字符串。我在这里错过了什么?
  • @mad_ __repr__ 完全无关
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-27
  • 2010-12-28
  • 1970-01-01
  • 1970-01-01
  • 2014-02-25
  • 2015-06-20
相关资源
最近更新 更多