【问题标题】:is there a time when the `is` operator can return false with two similar strings in Python? [duplicate]是否有一段时间,`is` 运算符可以在 Python 中使用两个相似的字符串返回 false? [复制]
【发布时间】:2013-11-22 21:01:16
【问题描述】:

我正在编辑一些代码,以便一目了然,我想我应该将所有 char=="|" 更改为 char is "|"。我知道这看起来像是我把它弄得太笨了,但它看起来确实更好。无论如何,我决定最后一次pycheck,我收到了这个警告:

Warnings...

test.py:7: Using is |, may not always work
Processing module test (test.py)...

对于我的生活,我无法想象"|" is "|" 会返回False 的情况,除非你开始冒险使用多字节字符编码、CJK 字符等,如果我没记错的话。 还有其他我错过的情况吗?

【问题讨论】:

  • 不要使用is 来检查是否相等。即使它在实现 X 中有效,也可能在实现 Y 中无效。
  • pycheck 是否认为strings 是不可变的? char is "|" 在我看来更好。
  • 那个重复的标记是可取的。

标签: python string comparison


【解决方案1】:

== 将检查两边的值是否相等,但is 将检查两个变量是否指向同一个引用。因此,它们都是出于完全不同的目的。例如,

a = "aa"
b = "aa"
print a, b, id(a), id(b)
print a == b
print a is b

在我的机器上输出

aa aa 140634964365520 140634964365520
True
True

由于ab 指向相同的字符串数据(字符串在Python 中是不可变的),python 优化以使用相同的对象。这就是为什么is== 都返回True。在哪里

a = "aa"
b = "aaa"[:2]
print a, b, id(a), id(b)
print a == b
print a is b

在我的机器上输出

aa aa 139680667038464 139680667014248
True
False

虽然ab 有相同的数据(相等),但在内存中它们存储在不同的地方(不同的引用或两个不同的对象)。

所以,永远不要使用is 运算符来检查是否相等。

【讨论】:

  • 次要挑剔:内存存储位置或多或少无关紧要。相关的一点是它们是两个独立的对象。
  • @LennartRegebro 谢谢 :) 在我的回答中也添加了这一点。
  • 我认为 Guido 错过了那里的优化。解释器应该已经认识到切片已经被实习并因此重用它......无论如何,现在更清楚了。
  • @Segfault,但是每次 每次有人对字符串进行切片以匹配现有字符串的几次时,这样做是否会产生成本?仅仅因为有对它的引用并不意味着它也被拘留了。
【解决方案2】:

在 CPython 中,所有的单个字符串都是 intern 的,并且对于相同的字符串(字符)应该始终具有相同的 id

这只是一个实现细节,不应依赖。

几个地方你可能想检查两个字符串的身份是否相同,但你的用例不是其中之一

Python 2.7.2 (1.9+dfsg-1, Jun 19 2012, 23:23:45)
[PyPy 1.9.0 with GCC 4.7.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``"let's not be obscure, unless we
really need to"''
>>>> a = "|"
>>>> a is "|"
False

【讨论】:

  • 这是否意味着pypy 没有实习生字符串?
【解决方案3】:

我将这里的问题解释为“我实际上在哪里使用 'is' 来检查事物?”。

“is”检查通常在函数的默认命名参数为 None 并且您想查看是否为函数提供了某些内容时使用。无总是无。如果他们给出 0 或 [] 或 '',则这些东西的计算结果为 False。

False == 0 == bool('') == bool([]) == bool(None)

返回

True

因此,如果函数的用户希望函数像通常对此类参数一样继续运行,则检查变量的布尔值不会给您所需的行为。 None 就像一个哨兵来检查函数是否有故意提供的参数。当您将变量分配给可变的空容器对象时,此检查特别有用。

例如:

def foo(fn_list=None):
    if fn_list is None:
         fn_list = []
    fn_list.append('foo')
    return fn_list

所以

a is b

和检查一样

id(a) == id(b)

如果计算结果为 True,则它们是同一个对象,因为它们都指向内存中的同一个位置。正如其他人指出的那样,不要使用 is 来检查相等性,因为实现可能会有所不同,并且在语义上,您不关心它是否是同一个对象,您关心的是这两个项目是否相等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-06
    • 2021-01-03
    • 1970-01-01
    • 2011-04-25
    • 2017-02-09
    • 2018-06-18
    相关资源
    最近更新 更多