我有一个 Python 程序,其中将两个变量设置为值'public'
。在条件表达式中,我有一个比较var1 is var2
,但是比较失败,但是如果将其更改为var1 == var2
它将返回True
。
现在,如果我打开 Python 解释器并进行相同的 “是” 比较,则此操作成功。
>>> s1 = 'public'
>>> s2 = 'public'
>>> s2 is s1
True
我在这里想念什么?
is
身份测试, ==
是平等测试。您的代码中发生的情况将在解释器中进行模拟,如下所示:
>>> a = 'pub'
>>> b = ''.join(['p', 'u', 'b'])
>>> a == b
True
>>> a is b
False
所以,难怪他们不一样吧?
换句话说: is
id(a) == id(b)
这里其他的答案是正确的: is
用于识别比较,而==
用于相等比较。由于您关心的是相等性(两个字符串应包含相同的字符),因此在这种情况下, is
运算符就是错误的,您应该改用==
。
之所以is
交互is
工作是因为(大多数)字符串文字默认情况下是interned 。从维基百科:
插入的字符串可以加速字符串比较,这有时是严重依赖带有字符串键的哈希表的应用程序(例如编译器和动态编程语言运行时)的性能瓶颈。在不进行实习的情况下,检查两个不同的字符串是否相等涉及检查两个字符串的每个字符。这很慢,原因有几个:字符串的长度固有地为 O(n);它通常需要从多个内存区域进行读取,这需要时间。并且读取将填满处理器缓存,这意味着可用于其他需求的缓存较少。对于插入的字符串,在原始的内部操作之后,一个简单的对象身份测试就足够了;这通常以指针相等性测试的形式实现,通常仅是一条机器指令,根本没有内存引用。
因此,当程序中有两个具有相同值的字符串文字(在程序源代码中逐字键入的单词,并用引号引起来)时,Python 编译器将自动内插这些字符串,使它们都存储在相同的位置内存位置。 (请注意,这种情况并非总是会发生,并且发生这种情况的规则非常复杂,因此请不要在生产代码中依赖此行为!)
由于在您的交互式会话中,两个字符串实际上都存储在相同的存储位置中,因此它们具有相同的标识 ,因此is
运算符可以按预期工作。但是,如果您通过其他方法构造字符串(即使该字符串包含完全相同的字符),则该字符串可能相等 ,但它不是同一字符串 - 也就是说,它具有不同的标识 ,因为它是存储在内存中的其他位置。
is
关键字是对象标识的测试,而==
是值比较。
如果使用is
,则当且仅当对象是同一对象时,结果才为 true。但是,只要对象的值相同,则==
将为 true。
最后要注意的一点是,您可以使用 intern 函数来确保您引用了相同的字符串:
>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True
如上所述,您可能不应该做的就是确定字符串的相等性。但是,这可能有助于知道你是否有某种奇怪的要求使用is
。
请注意,内部函数已从内置函数移至 Python 3 的sys
模块中。
is
身份测试, ==
是平等测试。这意味着这is
一种检查两种事物是相同的还是等同的方法。
假设你已经有了一个简单的person
对象。如果它的名字叫 “Jack” 并且是 “23” 岁,则相当于另一个 23 岁的 Jack,但不是同一个人。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
return self.name == other.name and self.age == other.age
jack1 = Person('Jack', 23)
jack2 = Person('Jack', 23)
jack1 == jack2 #True
jack1 is jack2 #False
他们是同一年龄,但他们不是同一个人。一个字符串可能等效于另一个,但它不是同一对象。
这是一个旁注,但是在惯用的 python 中,您经常会看到类似以下内容:
if x is None:
# some clauses
这是安全的,因为保证存在 Null 对象的一个实例(即 None) 。
如果不确定自己在做什么,请使用 '=='。如果您对此有更多了解,可以对已知对象(例如 “无”)使用 “is”。
否则,您将最终想知道为什么事情不起作用以及为什么会发生这种情况:
>>> a = 1
>>> b = 1
>>> b is a
True
>>> a = 6000
>>> b = 6000
>>> b is a
False
我什至不确定在不同的 python 版本 / 实现之间是否可以保证某些事情保持不变。
从我与蟒蛇的经验有限, is
用来比较两个对象,看看他们,而不是两个不同的对象具有相同的值相同的对象。 ==
用于确定值是否相同。
这是一个很好的例子:
>>> s1 = u'public'
>>> s2 = 'public'
>>> s1 is s2
False
>>> s1 == s2
True
s1
是 unicode 字符串,而s2
是普通字符串。它们不是同一类型,但是具有相同的值。
我认为这与以下事实有关:当 “is” 比较结果为 false 时,将使用两个不同的对象。如果评估结果为 true,则表示在内部使用的是完全相同的对象,而不是创建新的对象,这可能是因为您在不到 2 秒的时间内创建了它们,并且在优化和使用相同的对象。
这就是为什么您应该使用等于运算符==
而不是is
来比较字符串对象的值的原因。
>>> s = 'one'
>>> s2 = 'two'
>>> s is s2
False
>>> s2 = s2.replace('two', 'one')
>>> s2
'one'
>>> s2 is s
False
>>>
在此示例中,我制作了 s2,它是一个以前等于'one' 的不同字符串对象,但它与s
,因为解释器未使用同一对象,因为我最初并未将其分配给'one'。 ,如果有的话,它们会使它们成为同一对象。
我相信这被称为 “interned” 字符串。在优化模式下,Python 会这样做,Java 也会这样做,C 和 C ++ 也会这样做。
如果您使用两个相同的字符串,而不是通过创建两个字符串对象来浪费内存,则具有相同内容的所有已嵌入字符串都指向相同的内存。
这导致 Python“is” 运算符返回 True,因为两个内容相同的字符串指向同一个字符串对象。这也将在 Java 和 C 语言中发生。
但是,这仅对节省内存有用。您不能依靠它来测试字符串是否相等,因为各种解释器和编译器以及 JIT 引擎不能总是这样做。