【问题标题】:Python class: Why can't I use the method len() inside __eq__(self, other)?Python 类:为什么我不能在 __eq__(self, other) 中使用方法 len()?
【发布时间】:2015-12-07 05:16:48
【问题描述】:

https://gist.github.com/rjurney/1e8454af8e44312d02d7

class FrozenSortedTuple:
  """A frozenset that cares about order of tuples. And is not actually frozen."""
  def __init__(self, vals):
    if type(vals) not in [list, set, tuple]:
      raise Exception('Value not a list or set')
    self.vals = list(vals)

  def __eq__(self, other):
    if len(self.vals) != len(other):
      return False
    if type(self.vals) != type(other):
      return False
    if type(other) not in [list, set, tuple]:
      return False
    other_list = list(other)
    for i,item in enumerate(self.vals):
      if item != other_list[i]:
        return False
    return True

在 iPython 中调用:

In [2]: a = ['a','b']

In [3]: b = ['b','a']

In [4]: c = ['a','b']

In [5]: a == b
Out[5]: False

In [6]: FrozenSortedTuple(a)
Out[6]: <__main__.FrozenSortedTuple instance at 0x103c56200>

In [7]: fa = FrozenSortedTuple(a)

In [8]: fb = FrozenSortedTuple(b)

In [9]: fa == fb

错误:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-9-317181571e4d> in <module>()
----> 1 fa == fb

<ipython-input-1-ef99f0af5061> in __eq__(self, other)
     15 
     16   def __eq__(self, other):
---> 17     if len(self.vals) != len(other):
     18       return False
     19     if type(self.vals) != type(other):

AttributeError: FrozenSortedTuple instance has no attribute '__len__'

我很困惑。

【问题讨论】:

  • 问题不在于“你不能在__eq__ 中调用len”。问题是“你根本不能在任何地方打电话给len”,因为你从来没有为这门课实施过它。 len(fa) 会以同样的方式在主范围内失败。
  • 为什么所有全局函数都会在一个类中消失?
  • 哦!我知道了。谢谢。
  • 等等,我没有。我不是在 self 上调用 len(),也不是在调用 ... 是的,我是。好,谢谢!您可以在答案而不是评论中做出答案吗?

标签: python class python-2.7 oop variable-length


【解决方案1】:

如果您尝试直接比较两个 FrozenSortedTuples 值的结构和内容,请将您的所有 other 实例更改为 other.vals

def __eq__(self, other):
    if len(self.vals) != len(other.vals):
      return False
    if type(self.vals) != type(other.vals):
      return False
    if type(other.vals) not in [list, set, tuple]:
      return False
    other_list = list(other.vals)
    for i,item in enumerate(self.vals):
      if item != other_list[i]:
        return False
    return True

当然,如果other 不是 FrozenSortedTuple,这将无法工作。例如,fa == 23 不起作用,因为数字 23 没有“vals”属性。

【讨论】:

  • 或者直接实现def __len__(self): return len(self.vals)
  • 是的,但随后if type(self.vals) != type(other) 将无法按预期工作,以此类推他的所有其他条件。
  • 是的,其余的代码当然需要相应地调整。
【解决方案2】:

按照您定义__eq__(self, other) 的方式,只有当 other 是您要包装的类型(即列表、集合或元组)的实例时才能实现相等。您通过比较FrozenSortedTuple 的两个实例来触发错误。错误消息告诉您无法在此类实例上调用 len(),这是因为您尚未在类中定义方法 __len__(self)

如果您为您的班级定义__len__(),它将起作用。请参阅the Python Documentation(此链接到 2.7 文档,但它在 Python 3.x 中的工作方式应该相同) 或者,您可以比较 len(self.vals) == len(other.vals)FrozenSortedTuple 实例。

【讨论】:

    【解决方案3】:

    谢谢,根据其他答案,我想要的是:

    class FrozenSortedTuple:
      """A frozenset that cares about order of tuples. And is not actually frozen."""
      def __init__(self, vals):
        if type(vals) not in [list, set, tuple]:
          raise Exception('Value not a list or set')
        self.vals = vals
    
      def __len__(self):
        return len(self.vals)
    
      def __iter__(self):
        return iter(self.vals)
    
      def __getitem__(self, key):
        return list(self.vals)[key]
    
      def __eq__(self, other):
        if len(self) != len(other):
          print "len(self)"
          return False
    
        for i,item in enumerate(self.vals):
          if item != other[i]:
            return False
        return True
    
      def __str__(self):
        str_val = str()
        for val in self:
          str_val += str(val)
        return str_val
    
      def __hash__(self):
        return hash(str(self))
    

    测试:

    # FrozenSortedTuple Tests
    a = ['a','b']
    b = ['b','a']
    c = ['a','b']
    
    fa = FrozenSortedTuple(a)
    fb = FrozenSortedTuple(b)
    fc = FrozenSortedTuple(c)
    
    fa == fb
    fa == fc
    fa == ['a','b']
    fa == ['b','a']
    fa == ('a','b')
    fa == ('b','a')
    
    a = set([fa, fb, fc])
    b = set([fa, fb, fc])
    c = set([fa, fc, fb])
    a == b
    b == c
    fa in a
    fb in b
    
    d = set([fb])
    fa in d
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-29
      • 2015-03-20
      • 2017-02-09
      • 2020-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多