python set.__contains__ 的意外行为

发布于 2024-12-06 14:07:55 字数 951 浏览 1 评论 0原文

借用 __contains__ 文档中的文档

print set.__contains__.__doc__
x.__contains__(y) <==> y in x.

这对于原始对象(如 int、basestring 等)似乎工作得很好。但对于定义 __ne__的用户定义对象>__eq__ 方法,我得到了意想不到的行为。这是示例代码:

class CA(object):
  def __init__(self,name):
    self.name = name

  def __eq__(self,other):
    if self.name == other.name:
      return True
    return False

  def __ne__(self,other):
    return not self.__eq__(other)

obj1 = CA('hello')
obj2 = CA('hello')

theList = [obj1,]
theSet = set(theList)

# Test 1: list
print (obj2 in theList)  # return True

# Test 2: set weird
print (obj2 in theSet)  # return False  unexpected

# Test 3: iterating over the set
found = False
for x in theSet:
  if x == obj2:
    found = True

print found   # return True

# Test 4: Typcasting the set to a list
print (obj2 in list(theSet))  # return True

那么这是一个错误还是一个功能?

Borrowing the documentation from the __contains__ documentation

print set.__contains__.__doc__
x.__contains__(y) <==> y in x.

This seems to work fine for primitive objects such as int, basestring, etc. But for user-defined objects that define the __ne__ and __eq__ methods, I get unexpected behavior. Here is a sample code:

class CA(object):
  def __init__(self,name):
    self.name = name

  def __eq__(self,other):
    if self.name == other.name:
      return True
    return False

  def __ne__(self,other):
    return not self.__eq__(other)

obj1 = CA('hello')
obj2 = CA('hello')

theList = [obj1,]
theSet = set(theList)

# Test 1: list
print (obj2 in theList)  # return True

# Test 2: set weird
print (obj2 in theSet)  # return False  unexpected

# Test 3: iterating over the set
found = False
for x in theSet:
  if x == obj2:
    found = True

print found   # return True

# Test 4: Typcasting the set to a list
print (obj2 in list(theSet))  # return True

So is this a bug or a feature?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

故事和酒 2024-12-13 14:07:55

对于 setdicts,您需要定义 __hash__。任何两个相等的对象都应该具有相同的哈希值,以便在 setdicts 中获得一致/预期的行为。

我建议使用 _key 方法,然后在需要比较项目部分的任何地方引用该方法,就像您从 __ne____eq__ 一样code> 而不是重新实现它:

class CA(object):
  def __init__(self,name):
    self.name = name

  def _key(self):
    return type(self), self.name

  def __hash__(self):
    return hash(self._key())

  def __eq__(self,other):
    if self._key() == other._key():
      return True
    return False

  def __ne__(self,other):
    return not self.__eq__(other)

For sets and dicts, you need to define __hash__. Any two objects that are equal should hash the same in order to get consistent / expected behavior in sets and dicts.

I would reccomend using a _key method, and then just referencing that anywhere you need the part of the item to compare, just as you call __eq__ from __ne__ instead of reimplementing it:

class CA(object):
  def __init__(self,name):
    self.name = name

  def _key(self):
    return type(self), self.name

  def __hash__(self):
    return hash(self._key())

  def __eq__(self,other):
    if self._key() == other._key():
      return True
    return False

  def __ne__(self,other):
    return not self.__eq__(other)
故事灯 2024-12-13 14:07:55

这是因为 CA 没有实现 __hash__ :

一个合理的实现是

def __hash__(self):
    return hash(self.name)

This is because CA doesn't implement __hash__

A sensible implementation would be:

def __hash__(self):
    return hash(self.name)
提笔书几行 2024-12-13 14:07:55

集合散列它的元素以允许快速查找。您必须覆盖 __hash__ 方法,以便可以找到元素:

class CA(object):
  def __hash__(self):
    return hash(self.name)

列表不使用散列,而是像 for 循环一样比较每个元素。

A set hashes it's elements to allow a fast lookup. You have to overwrite the __hash__ method so that a element can be found:

class CA(object):
  def __hash__(self):
    return hash(self.name)

Lists don't use hashing, but compare each element like your for loop does.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文