【问题标题】:Precise Membership Test in PythonPython中的精确成员资格测试
【发布时间】:2015-08-06 16:36:12
【问题描述】:

in 运算符使用比较来测试等价性,但 Python 的比较并不精确,因为 True == 1 和 0 == False,产生 -

>>> True in [ 1 ]
True
>>> False in [ 0 ]
True
>>> 1 in [ True ]
True
>>> 0 in [ False ]
True

而我需要一个精确的比较(类似于其他语言中的 ===),这将在上述所有示例中产生 False。我当然可以遍历列表:

res = False
for member in mylist:
    if subject == member and type( subject ) == type( member ):
        res = True
        break

这显然比使用内置 in 运算符效率低得多,即使我将其打包为列表理解。是否有 in 的本地替代方案,例如列表方法或调整 in 行为以获得所需结果的某种方式?

in 运算符在我的案例中用于测试所有列表成员的唯一性,因此本地唯一性测试也可以。

重要提示:该列表可能包含可变值,因此不能使用set

Python 版本是 3.4,对于在 2.7 上运行的解决方案来说也很棒。

编辑给所有建议使用IS的人:

  1. 我正在寻找 a in b 的非迭代原生替代方案。
  2. is 运算符与这种情况无关。例如,在以下情况下,in 可以正常工作,但 is 不会:

    >>> [1,2] in [[1,2]]
    True
    

请在回答之前阅读问题...

【问题讨论】:

  • 您正在寻找is 运算符:if any(x is True for x in l): ...
  • @Blender 在我说我正在寻找本机解决方案的问题中,我知道如何迭代列表,正如您从问题中看到的那样......此外,is 不会不适用于列表、字典、类等其他类型,我需要的比较是根据问题,类似于其他语言的 ===
  • YourClass.__eq__ 总是返回True 的对象的情况下=== 将如何工作?
  • @Blender,就像in 一样。到目前为止,我发现in 中断的唯一情况是您希望 1 和 True、0 和 False 不相等。

标签: python


【解决方案1】:

in 根本不测​​试等效性。它检查项目是否在容器中。示例:

>>> 5 in [1,2,3,4,5]
True
>>> 6 in [1,2,3,4,5]
False
>>> True in {True, False}
True
>>> "k" in ("b","c")
True

你要找的是is

>>> True == 1
True
>>> True is 1
False
>>> False == 0
True
>>> False is 0
False

编辑

阅读您的编辑后,我认为 python 库中没有内置的东西可以满足您的需求。你想要的基本上是区分intbool (True, False). 但是python 本身将TrueFalse 视为整数。这是因为boolint 的子类。这就是为什么True == 1False==0 评估为真的原因。你甚至可以这样做:

>>> isinstance ( True, int)
True

我想不出比您自己的解决方案更好的方法了,但是,如果您的列表确定包含不超过一次的任何项目,您可以使用list.index()

try:
    index_val = mylist.index(subject)
except ValueError:
    index_val = None

if (index_val!=None):
    return type(subject) == type(member)

由于 index 是内置的,它可能会快一点,虽然相当不优雅。

【讨论】:

    【解决方案2】:

    Python in 运算符是精确的,您所抱怨的行为是完全可以预料的,因为 boolint 的子类。

    下面是官方Python documentation描述boolean类型的摘录:

    布尔值

    这些代表真值 False 和 True。表示值 False 和 True 的两个对象是唯一的布尔对象。布尔类型是纯整数的子类型,布尔值在几乎所有上下文中的行为分别类似于值 0 和 1,例外是当转换为字符串时,返回字符串“False”或“True”,分别。

    你也可以看看PEP 285

    【讨论】:

    • 谢谢,这解释了这种行为。顺便说一句,我没有抱怨,我只需要实现一些代码来测试 json 数组成员的唯一性;在 json [1,true] 中,所有成员都是唯一的,1 in [2,true] 应该返回 false,因此强制“我的”in 函数,最终效率低于它,例如在 javascript 中,因为 Python 缺少原生 === 运算符...
    • 对不起,avnr,我应该使用“体验”而不是“抱怨”。但是,根据列表中存在的数据类型,您可以尝试将 item in iterable 替换为 str(item) in map(str, iterable)
    【解决方案3】:

    您正在寻找is 运算符:

    if any(x is True for x in l):
        ...
    

    但是,is 并不完全是来自其他语言的===is 检查身份,而不仅仅是没有类型强制的相等性。由于CPython使用字符串和整数interning,两个相等的对象可能不是同一个对象:

    In [19]: a = '12'
    
    In [20]: b = '123'
    
    In [21]: a += '3'
    
    In [22]: a is b
    Out[22]: False
    
    In [23]: a == b
    Out[23]: True
    
    In [27]: 100001 is 100000 + 1
    Out[27]: False
    
    In [28]: 100001 == 100000 + 1
    Out[28]: True
    

    在 Python 3 中,NoneTrueFalse 本质上是单例,因此使用 is 来区分 True1 将非常有效。然而,在 Python 2 中,这是可能的:

    In [29]: True = 1
    
    In [31]: True is 1
    Out[31]: True
    

    平等可以被__eq__方法覆盖,所以你可以定义一个与其他任何对象相等的对象:

    In [1]: %paste
        class Test(object):
            def __eq__(self, other):
                return True
    
    ## -- End pasted text --
    
    In [2]: x = Test()
    
    In [3]: x == None
    Out[3]: True
    
    In [4]: x == True
    Out[4]: True
    
    In [5]: x == False
    Out[5]: True
    

    在这种情况下,=== 将如何工作?没有通用的解决方案,因此 Python 没有内置的列表方法可以满足您的需求。

    【讨论】:

    • 主题 == 成员和类型(主题)== 类型(成员)
    猜你喜欢
    • 2011-10-29
    • 2012-03-02
    • 1970-01-01
    • 2021-10-10
    • 2018-08-11
    • 2021-11-27
    • 2011-09-10
    • 2020-05-05
    相关资源
    最近更新 更多