【问题标题】:how to compare for equality for None objects in custom class in python?如何比较python中自定义类中None对象的相等性?
【发布时间】:2013-12-20 07:01:59
【问题描述】:

我正在为 python 编写一个Queue 数据结构,纯粹是为了学习目的。这是我的class。当我比较两个 Queue 对象是否相等时,出现错误。我认为错误会弹出,因为我没有比较 None 在我的 __eq__ 中。但是我如何检查 Nonereturn 一致。事实上,我在后台使用list 并调用它的__eq__,认为它应该像这里所示那样小心,但它没有

>>> l=[1,2,3]
>>> l2=None
>>> l==l2
False

这是我的课:

@functools.total_ordering
class Queue(Abstractstruc,Iterator):

    def __init__(self,value=[],**kwargs):
        objecttype = kwargs.get("objecttype",object)
        self.container=[]
        self.__klass=objecttype().__class__.__name__
        self.concat(value)


    def add(self, data):
        if (data.__class__.__name__==self.__klass or self.__klass=="object"): 
            self.container.append(data)
        else:
            raise Exception("wrong type being added")

    def __add__(self,other):
        return Queue(self.container + other.container)


    def __iadd__(self,other):
        for i in other.container:
            self.add(i)
        return self


    def  remove(self):
        return self.container.pop(0)


    def peek(self):
        return self.container[0]


    def __getitem__(self,index):
        return self.container[index]


    def __iter__(self):
        return Iterator(self.container)

    def concat(self,value):
        for i in value:
            self.add(i)

    def __bool__(self):
        return len(self.container)>0

    def __len__(self):
        return len(self.container)


    def __deepcopy__(self,memo):
        return Queue(copy.deepcopy(self.container,memo))

    def __lt__(self,other):
        return self.container.__lt__(other.container)

    def __eq__(self, other):
        return self.container.__eq__(other.container)

但是当我尝试使用上面的类进行比较时,我得到:

>>> from queue import Queue
>>> q = Queue([1,2,3])
>>> q
>>> print q
<Queue: [1, 2, 3]>
>>> q1 = None
>>> q==q1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "queue.py", line 65, in __eq__
    return self.container.__eq__(other.container)
AttributeError: 'NoneType' object has no attribute 'container'
>>> 

【问题讨论】:

    标签: python class object comparison equals


    【解决方案1】:

    告诉 Python 你不知道如何与其他类型进行比较:

    def __eq__(self, other):
        if not isinstance(other, Queue):
            return NotImplemented
        return self.container.__eq__(other.container)
    

    您可以考虑检查hasattr(other, 'container') 而不是isinstance,或者查看AttributeError

    但重要的是,与其他答案推荐的不同,当other 不是队列时,您想要return False。如果你返回NotImplemented,Python 会给other 一个检查相等性的机会;如果您返回 False,则不会。区分“这些对象是否相等”问题的三个可能答案:是的,否,我不知道。

    您将希望在您的__lt__ 中执行类似的操作,其中差异更加明显:如果您从__lt____eq__ 返回False,则__gt__ 由@987654335 插入@ 将返回 True - 即使您无法进行比较。如果你从他们两个返回NotImplemented,它也将是NotImplemented

    【讨论】:

    【解决方案2】:

    你的问题是你如何实现__eq__

    看看这段代码:

    q = Queue([1,2,3])
    q1 = None
    q==q1
    

    让我们将其重写为等价:

    q = Queue([1,2,3])
    q == None
    

    现在,在Queue.__eq__ 我们有:

    def __eq__(self, other):
        return self.container.__eq__(other.container)
    

    但是otherNone,也就是说return语句在调用:

    self.container.__eq__(None.container)
    

    正如您的错误正确指出的那样:

    'NoneType' object has no attribute 'container'
    

    因为没有! None 没有容器属性。

    所以,如何做到这一点,取决于你想如何对待它。现在,很明显,Queue 对象如果被定义就不能是 None,所以:

    return other is not None and self.container.__eq__(other.container)
    

    如果otherNone,将延迟评估,并在评估and 之后的表达式部分之前返回False。否则,它将执行评估。但是,如果other 不是Queue 类型(或者更准确地说,其他对象没有container 属性),您将遇到其他问题,例如:

    q = Queue([1,2,3])
    q == 1
    >>> AttributeError: 'int' object has no attribute 'container'
    

    所以...根据您的逻辑,如果 Queue 不能与其他类型“相等”(只有您可以说),您可以检查正确的类型如下:

    return other is not None and type(self) == type(other) and self.container.__eq__(other.container)
    

    但是...NoneNoneType,因此它永远不能与 Queue 属于同一类型。所以我们可以再次将其缩短为:

    return type(self) == type(other) and self.container.__eq__(other.container)
    

    编辑:根据 mglisons cmets:

    这可以通过使用常规的等式语句变得更加 Pythonic:

    return type(self) == type(other) and self.container == other.container
    

    他们还提出了一个关于使用type 来检查美容的好观点。如果您确定Queue 永远不会被子类化(这很难说明)。您可以使用异常处理来有效地捕获AttributeError,如下所示:

    def __eq__(self, other):
        try:
            return self.container == other.container
        except AttributeError:
            return False    # There is no 'container' attribute, so can't be equal
        except:
            raise           # Another error occured, better pay it forward
    

    以上内容可能被认为有点过度设计,但从安全性和可重复性的角度来看,这可能是解决此问题的更好方法之一。

    或者使用hasattr 的更好、更短的方法(我最初应该想到的)是:

    return hasattr(other, 'container') and self.container == other.container
    

    【讨论】:

    • 当你可以做self.container == ... 时,为什么还要self.container.__eq__(...)?另外,我不确定是否推荐type 的平等。子类等呢?
    • @mgilson 我只是在重用 OPs 代码。您可以将其重写为self.container ==。你让我用type 检查。你会建议什么?
    • @LegoStormtroopr -- 我想你可以试试hasattr 看看other 是否有container 属性并依赖duck-typing。
    • @user1988876 -- 你的意思是isinstance?当然,你可以试试。例如return isinstance(other, Queue) and self.container == other.container
    • @user1988876 很大程度上取决于程序员的想法。如果一个Queue 只能等于其他Queues,但不能等于它们的子类,那么type(self) == type(other) 是有效的。但这取决于你。这里有几种方法,尽管我在上述评论中链接的问题建议反对 isinstance 和类似方法。
    【解决方案3】:

    你可以做类似的事情

        def __eq__(self,other):
            if other is None: return False
            return self.container.__eq__(other.container)
    

    您可能还想做类似的事情

    if not isinstance(other,Queue): return False
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多