2012-10-25 84 views
6

是运算符比较两个对象的内存地址是否相同,则返回true否则返回false。 代码#1是运算符混淆

>>a="poi" 
>>b="poi" 
a is b 
true 

我已经创建了两个对象,其内容是相同的,但它们是在不同的内存地址的整个生活。 那么为什么操作符返回true?它不应该返回错误。 就像这个代码

>>ktr = "today is a fine day" 
>>ptr = "today is a fine day" 
>>ktr is ptr 
false 
+0

在实践中,除非你正在做一些相当复杂的事情,否则你可能永远不会使用'is'。大概需要'=='来进行大多数的相等比较。 – dkamins

+0

@dkamins:测试'None'的推荐方法是'':'some_var是None'(因为只有一个'None'的实例)。我会说这是一个很常见的情况。 – voithos

+0

@voithos真的 - 我一直都在使用它(而不是'''),甚至没有想到它!但除此之外...... – dkamins

回答

5

我认为它与string interning.有关。本质上,其思想是仅存储每个不同字符串的单个副本,以提高某些操作的性能。

基本上,a is b工作的原因是因为(正如您可能已经猜到的那样),在这两种情况下都有Python引用的单个不可变字符串。当一个字符串很大(以及其他一些我不明白的因素时,很可能),这不会完成,这就是为什么您的第二个示例返回False。

编辑:而事实上,奇怪的行为似乎是互动环境的副作用。如果您将相同的代码放入Python脚本中,则a is bktr is ptr都会返回True。

a="poi" 
b="poi" 
print a is b # Prints 'True' 

ktr = "today is a fine day" 
ptr = "today is a fine day" 
print ktr is ptr # Prints 'True' 

这很有道理,因为Python可以很容易地解析源文件并在其中查找重复的字符串文字。如果您动态创建字符串,则即使在脚本中它的行为也不同。

a="p" + "oi" 
b="po" + "i" 
print a is b # Oddly enough, prints 'True' 

ktr = "today is" + " a fine day" 
ptr = "today is a f" + "ine day" 
print ktr is ptr # Prints 'False' 

至于为什么a is b仍然导致真,也许分配的字符串足够小,以保证通过实习集合的快速搜索,而另一种是不?

+1

关于'a =“p”+“oi”; b =“po”+“i”',编译器通过在代码对象中存储两个对''poi''的引用来优化简单字符串连接,这些引用被放置在适当位置。 ''今天是一个美好的一天“'因为它包含空格(即非名字符)而没有被实施。 – eryksun

3

is是身份鉴定。它将工作在更小的某些字符串(因为缓存)而不是更大的其他字符串。由于str不是ptr。 [感谢erykson]

参见此代码:

>>> import dis 
>>> def fun(): 
... str = 'today is a fine day' 
... ptr = 'today is a fine day' 
... return (str is ptr) 
... 
>>> dis.dis(fun) 
    2   0 LOAD_CONST    1 ('today is a fine day') 
       3 STORE_FAST    0 (str) 

    3   6 LOAD_CONST    1 ('today is a fine day') 
       9 STORE_FAST    1 (ptr) 

    4   12 LOAD_FAST    0 (str) 
      15 LOAD_FAST    1 (ptr) 
      18 COMPARE_OP    8 (is) 
      21 RETURN_VALUE 

>>> id(str) 
26652288 
>>> id(ptr) 
27604736 
#hence this comparison returns false: ptr is str 

通知strptr的ID不同。

BUT:x和y的

>>> x = "poi" 
>>> y = "poi" 
>>> id(x) 
26650592 
>>> id(y) 
26650592 
#hence this comparison returns true : x is y 

ID相同。因此,is运算符工作在“ids”而不是“equalities”上

请参阅下面的链接,了解python何时和为什么会为相同的字符串分配不同的内存位置(也请阅读该问题)。在python2.x

When does python allocate new memory for identical strings

而且sys.intern上python3.x和intern应该帮助你分配的字符串相同的内存位置,该字符串的大小无关。

+0

这个字符串可以有多小/ – navyad

+0

你可以有一个空字符串'“”'。但这不是全部,因为两个字符串可以设置为相同的值,所以'is'返回'true',然后您可以修改一个并撤销修改,结果将不会是'true'更多。 –

+0

@MthetheAdams你不能修改'str'ing,它们是不可变的。您只能将名称指向新的字符串对象。 – agf

2

is不是==相同。

基本上,is检查两个对象是否相同,而==比较这些对象(字符串,如python中的所有内容,都是对象)的值。

所以你应该使用is当你真的知道你正在看什么对象(即你已经做出了对象,或者正在与None作为问题评论指出)比较,你想知道是否两个变量在内存中引用完全相同的对象

然而,在您的示例中,您正在查看Python正在幕后处理的str对象,因此,如果不深入研究python的工作原理,您就不会真正了解期望的结果。您会遇到与int s或float s相同的问题。其他答案在解释“幕后”内容(字符串实习)方面做得很好,但在日常编程中你大多不应该担心。

+1

那么为什么这两个例子不同呢?这不解释。 – agf

+0

@agf刚刚编辑 - 这是否解释我的意思是我的回答更好? –

1

请注意,这是CPython特定的优化。如果你想要你的代码是可移植的,你应该避免它。例如,在PyPy

>>>> a = "hi" 
>>>> b = "hi" 
>>>> a is b 
False 

另外值得指出的是,类似的事情发生了小整数

>>> a = 12 
>>> b = 12 
>>> a is b 
True 

再次你不应该依赖,因为其他的实现可能不包含这种优化。