python __eq__ 测试失败

Posted

技术标签:

【中文标题】python __eq__ 测试失败【英文标题】:python failing __eq__ test 【发布时间】:2020-01-28 20:05:59 【问题描述】:

我是 python 新手,正在学习使用 pytest。我有一个类定义为:

class Matrix:

    def __init__(self, *rows):
        row_length = len(rows[0])
        for row in rows:
            # TODO skip first
            if len(row) != row_length:
                raise SystemError("Rows does not have equal length")

        self._rows = [*rows]

    def __eq__(self, other):
        return isinstance(self, other.__class__) and \
               all([x == y for x, y in zip_longest(self._rows, other._rows)])

    # other methods omitted for simplicity...

我为__eq__(self, other) 写了一个测试,如下所示:

def test_eq():
    m1 = Matrix([[1,2,3],[4,5,6]])
    m2 = Matrix([1,2,3],[4,5,6])
    m3 = Matrix([1,2,3],[5,4,6])
    assert m1 == m2
    assert m2 == m1
    assert m2 != m3

Wich 应该通过,因为 m1m2 具有相同的行,而 m3 在第二行中存在差异。但是,当我运行此测试时,我有输出:

    def test_eq():
        m1 = Matrix([[1,2,3],[4,5,6]])
        m2 = Matrix([1,2,3],[4,5,6])
        m3 = Matrix([1,2,3],[5,4,6])
>       assert m1 == m2
E       assert <exercises.matrix.Matrix object at 0x10ccd67d0> == <exercises.matrix.Matrix object at 0x10ccd6810>

我在这里缺少什么?我正在使用 Python 3.7.4 和 pytest 版本 5.1.2。提前感谢您的 cmets/answers


注意:我根据 ggorlen 的回答更改了实现,但我遇到了类似的问题


【问题讨论】:

错误在您的.row 方法中,您没有向我们展示。 我认为情况并非如此,该方法已经过测试并且工作正常,但也许我传递了错误的参数。会检查。谢谢 您是否无意中忽略了row() 方法?如果该方法存在,请显示minimal reproducible example。 @ggorlen 我在课堂上添加了一些细节。请检查编辑。感谢您的宝贵时间 看起来同样的问题——不存在名为 _rows() 的方法。要么使用带括号的私有数据类_rows[],要么使用带括号的函数.row()。看我的回答。还有一个逻辑问题:如果other 矩阵的行数比self 多,您可能会得到误报,因为循环从不考虑多余的行。 【参考方案1】:

比较中的行应该是这样的:

for i, i_row in enumerate(self._rows):
    if i_row != other._rows[i]:
        return False

但是如果other 的行数比self 多,这仍然不会返回正确的结果,所以:

def __eq__(self, other):
    return isinstance(self, other.__class__) and \
           len(other._rows) == len(self._rows) and \
           all([x == y for x, y in zip(self._rows, other._rows)])

该属性名为_rows,我们需要使用[] 来索引列表,而不是括号。

一个可能更快的版本可以在比较失败的情况下提前退出:

def __eq__(self, other):
    if isinstance(self, other.__class__) and \
      len(other._rows) == len(self._rows):
        for i, row in enumerate(self._rows):
            if row != other._rows[i]:
                return False

        return True

    return False

在您的测试中,您可能有错字:

m1 = Matrix([[1,2,3],[4,5,6]]) # <-- this matrix has an extra `[]` wrapper
m2 = Matrix([1,2,3],[4,5,6])   # <-- but this one just uses flat lists

所以这些矩阵将不相等。


小建议:

在参数错误时引发ValueErrorArgumentError 而不是SystemError。 考虑使用Numpy.matrix 而不是滚动您自己的矩阵。

【讨论】:

我会试试你的解决方案。关于 Numpy.matrix,事实上这是一个练习,我应该只使用标准库函数。感谢您的宝贵时间 我按照您的建议更改了__eq__,但我遇到了同样的问题。检查版本 m1 = Matrix([[1,2,3],[4,5,6]])(额外的[]s)的错字修正了吗? 我相信这是列表列表的有效语法,但似乎不是。非常感谢,它现在可以工作了,你的解决方案比我的更干净优雅 zip_longest 方法效率较低,因为如果列表不相等,它会检查所有内容,直到遇到None == some_row_list。因此,如果我们只是预先检查长度,如果长度不同,我们可以立即返回,并且可以使用常规的zip,因为我们保证我们有相同的行数。它仍然不是最有效的解决方案,因为如果两个列表比较失败(使用常规循环而不是列表理解/any),则不会提前中断,但它应该是正确的。

以上是关于python __eq__ 测试失败的主要内容,如果未能解决你的问题,请参考以下文章

Python __super 黑魔法失败了

如何调试 Python 导入失败

机器人框架:无法使用 __eq__ 方法从类中获取关键字

Python - 导入包失败

我的python脚本以递归方式重命名文件,但失败了

从另一个目录导入的Python失败