2012-10-25 82 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 

再次你不應該依賴,因爲其他的實現可能不包含這種優化。