首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Python2.7如何比较列表中的项

Python2.7如何比较列表中的项
EN

Stack Overflow用户
提问于 2015-03-23 16:29:53
回答 4查看 758关注 0票数 7

今天我遇到了一个有趣的例子

代码语言:javascript
运行
复制
class TestableEq(object):
    def __init__(self):
        self.eq_run = False
    def __eq__(self, other):
        self.eq_run = True
        if isinstance(other, TestableEq):
            other.eq_run = True
        return self is other
代码语言:javascript
运行
复制
>>> eq = TestableEq()
>>> eq.eq_run
False
>>> eq == eq
True
>>> eq.eq_run
True
>>> eq = TestableEq()
>>> eq is eq
True
>>> eq.eq_run
False
>>> [eq] == [eq]
True
>>> eq.eq_run    # Should be True, right?
False
>>> (eq,) == (eq,)    # Maybe with tuples?
True
>>> eq.eq_run
False
>>> {'eq': eq} == {'eq': eq}    # dicts?
True
>>> eq.eq_run
False
>>> import numpy as np    # Surely NumPy works as expected
>>> np.array([eq]) == np.array([eq])
True
>>> eq.eq_run
False

因此,在Python中,容器内部的比较似乎是不同的。我预计对==的调用将使用每个对象的__eq__实现,否则有什么意义?另外

代码语言:javascript
运行
复制
class TestableEq2(object):
    def __init__(self):
        self.eq_run = False
    def __eq__(self, other):
        self.eq_run = True
        other.eq_run = True
        return False
代码语言:javascript
运行
复制
>>> eq = TestableEq2()
>>> [eq] == [eq]
True
>>> eq.eq_run
False
>>> eq == eq
False
>>> eq.eq_run
True

这是否意味着Python在容器的__eq__实现中使用__eq__?有办法绕道吗?

我的用例是,我正在构建一个继承自某些collections ABC的数据结构,我想编写测试以确保我的结构运行正常。我认为注入一个在比较时记录的值很简单,但令我惊讶的是,在检查时,测试失败了,以确保进行了比较。

编辑:我应该提到,这是在Python2.7上,但是我在3.3上看到了同样的行为。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-03-23 16:42:53

如果条目相同(==),CPython的底层实现将跳过列表中项的相等检查(is)。

CPython将此作为一种优化,假设标识意味着相等。

这在RichCompareBool中有记录,用于比较项:

注意:如果o1和o2是同一个对象,PyObject_RichCompareBool()总是返回1表示Py_EQ,0返回Py_NE。

来自listobject.c实现:

代码语言:javascript
运行
复制
/* Search for the first index where items are different */
for (i = 0; i < Py_SIZE(vl) && i < Py_SIZE(wl); i++) {
    int k = PyObject_RichCompareBool(vl->ob_item[i],
                                     wl->ob_item[i], Py_EQ);
    // k is 1 if objects are the same
    // because of RichCmopareBool's behaviour
    if (k < 0)
        return NULL;
    if (!k)
        break;
}

如您所见,只要RichCompareBool1 (True),就不会检查项目。

以及object.cPyObject_RichCompareBool的实现

代码语言:javascript
运行
复制
/* Quick result when objects are the same.
   Guarantees that identity implies equality. */
if (v == w) {
    if (op == Py_EQ)
        return 1;
    else if (op == Py_NE)
        return 0;
}
// ... actually deep-compare objects

若要重写此操作,您必须手动比较这些项。

票数 14
EN

Stack Overflow用户

发布于 2015-03-23 17:06:14

Python对序列相等性的测试如下:

代码语言:javascript
运行
复制
                 Lists identical?
                  /          \  
                 Y            N
                /              \
             Equal         Same length?
                            /       \  
                           Y         N
                          /           \
                  Items identical?   Not equal
                     /       \
                    Y         N
                   /           \
                Equal      Items equal?
                            /        \
                           Y          N
                          /            \
                       Equal        Not equal

您可以看到,如果两个序列的长度相同,则测试每个位置项的相等性,只测试,如果两个序列长度相同,则测试每个位置的项是不相同的。如果您想强制使用相等检查,您需要例如:

代码语言:javascript
运行
复制
all(item1 == item2 for item1, item2 in zip(list1, list2))
票数 10
EN

Stack Overflow用户

发布于 2015-03-23 16:43:16

如果x is y没有理由通过==合同调用x == y。Python正在抄这条捷径。

这可以通过在测试中创建一个eq1和一个eq2来验证/反驳,然后使用[eq1] == [eq2]

举个例子

代码语言:javascript
运行
复制
class TestableEq(object):
    def __init__(self):
        self.eq_run = False
    def __eq__(self, other):
        self.eq_run = True
        return True     # always assume equals for test

eq1 = TestableEq()
eq2 = TestableEq()
eq3 = TestableEq()

print [eq1] == [eq2]    # True
print eq1.eq_run        # True  - implies e1 == e2 
print eq2.eq_run        # False - but NOT e2 == e1

print [eq3] == [eq3]    # True
print eq3.eq_run        # False - implies NO e3 == e3

当项目是is时,不涉及==

与字典的区别可以用同样的方式来解释。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29215418

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档