无法比较 Python 中相同但重新声明的命名元组的类型

Unable to compare types of identical but redeclared namedtuples in Python

提问人:Drakes 提问时间:9/27/2021 更新时间:9/27/2021 访问量:60

问:

在开发差异引擎以识别非常大的数据结构中的差异时,我注意到相同但重新声明的比较行为不端。重新声明是不可避免的*。下面是一个最小的示例:typenamedtuplesnamedtuples

def test_named_tuples_same_type():
    from collections import namedtuple

    X = namedtuple("X", "x")
    a = X(1)

    # We are unable to avoid redeclaring X
    X = namedtuple("X", "x")
    b = X(1)

    print(repr(a))
    print(repr(b))
    # X(x=1)
    # X(x=1)

    assert isinstance(type(a), type(b))  # fail
    assert type(a) == type(b)  # fail

断言返回:

>       assert isinstance(type(a), type(b))  # fail
E       AssertionError: assert False
E        +  where False = isinstance(<class 'tests.test_deep_diff.X'>, <class 'tests.test_deep_diff.X'>)
E        +    where <class 'tests.test_deep_diff.X'> = type(X(x=1))
E        +    and   <class 'tests.test_deep_diff.X'> = type(X(x=1))

>       assert type(a) == type(b)  # fail
E       AssertionError: assert <class 'tests.test_deep_diff.X'> == <class 'tests.test_deep_diff.X'>

如何断言两者的类型相等或语义相等(无)?str(type())

*重新声明是不可避免的,因为它发生在不可修改的 'd 代码中,以生成不同的数据结构。namedtupleexec

python-3.x python-2.7 类型 相等 命名元组

评论

0赞 Drakes 9/27/2021
心想:我想知道如何显示类型的不同之处?
1赞 juanpa.arrivillaga 9/27/2021
“重新声明命名元组是不可避免的*。”对这一说法持高度怀疑态度。在任何情况下,请停止使用类型进行比较因为它们属于不同的类型。最简单的解决方案是不要让它们具有不同的类型,但是由于您(声称)这是不可避免的,因此您将不得不选择某种方式。首先,你应该定义“语义相等”的含义。然后在代码中实现该逻辑。
0赞 juanpa.arrivillaga 9/27/2021
而且,这里没有不当行为。这一切都是 Python 类型系统的基本语义所预料的。
0赞 Drakes 9/27/2021
这是不可避免的。这不是懒惰,无论是否相信都是不可避免的(顺便说一句,你错过了问题底部的*)。从短语中可以看出语义上的相等,但要明确地说,两个命名的元组都具有相同的模块,被命名,并采用一个参数 - 语义相等:它出现的 Python-equal 的超集。鉴于这些信息,您是否有想要分享的有用解决方案?Xx
0赞 juanpa.arrivillaga 9/27/2021
好吧,例如,它们应该具有相同的模块这一事实......那是什么意思?这些类是在同一模块中定义的?那么在模块中不应该与模块中定义的“语义类型”相同吗?X = namedtuple("X", "x")fooX = namedtuple("X", "x")bar

答:

0赞 juanpa.arrivillaga 9/27/2021 #1

目前尚不完全清楚你所说的语义等价是什么意思。但请考虑:

>>> from collections import namedtuple
>>> X1 = namedtuple("X", "x")
>>> X2 = namedtuple("X", "x")

然后,您可以使用以下功能:

>>> def equivalent_namedtuple_types(t1, t2):
...     return (t1.__name__, t1._fields) == (t2.__name__, t2._fields)
...
>>> equivalent_namedtuple_types(X1, X2)
True
>>>

从您的评论来看,您似乎也关心该属性。.__module__

评论

0赞 Drakes 9/27/2021
我参与了一个差异引擎。它实质上比较了两个对象,比如 和 。在检查字段是否相同之前,最合理的做法是首先检查类型是否相同。因此,给定这样一个在 99% 的时间内都能出色工作的比较器,重新声明的(在同一模块中)情况会出现并且是一个问题。鉴于我的 OP,我希望将这两个对象解释为相等,因为它们具有相同的“类”和相同的成员字段。abnamedtuple
0赞 juanpa.arrivillaga 9/27/2021
@Drakes好的,在检查元组是否相等之前,您可以使用上述方法检查它们是否具有相同的“类”。