簡體   English   中英

對帶有字符串的 `is` 運算符感到困惑

[英]Confused about `is` operator with strings

is運算符比較兩個對象的內存地址,如果它們相同則返回True 那么,為什么它不能與字符串一起可靠地工作? 代碼#1

>>> a = "poi"
>>> b = "poi"
>>> a is b
True

代碼#2

>>> ktr = "today is a fine day"
>>> ptr = "today is a fine day"
>>> ktr is ptr
False

我創建了兩個內容相同的字符串,但它們位於不同的內存地址上。 為什么的輸出is運營商並不一致?

我相信這與字符串實習有關。 本質上,這個想法是只存儲每個不同字符串的一個副本,以提高某些操作的性能。

基本上, 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仍然導致 True ,也許分配的字符串小到足以保證在內部集合中快速搜索,而另一個不是?

is是身份鑒定。 它適用於較小的一些字符串(由於緩存),但不適用於較大的其他字符串。 由於 str 不是 ptr。 [感謝埃里克森]

看到這個代碼:

>>> 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 是不同的。

但:

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

x 和 y 的 ID 相同。 因此is操作符適用於“ids”而不是“平等”

有關 Python 何時以及為何為相同字符串分配不同內存位置的討論,請參閱以下鏈接(也請閱讀問題)。

python什么時候為相同的字符串分配新的內存

此外, sys.intern上的 sys.intern 和 python2.x 上的intern應該可以幫助您在相同的內存位置分配字符串,而不管字符串的大小。

is一樣的==

基本上, is檢查兩個對象是否相同,而==比較這些對象的值(字符串,就像 Python 中的所有內容一樣,都是對象)。

所以你應該使用is當你真的知道你在看什么對象(即你已經創建了對象,或者正如問題注釋指出的那樣與None進行比較),並且你想知道兩個變量是否正在引用內存中完全相同的對象

但是,在您的示例中,您正在查看 python 在幕后處理的str對象,因此如果不深入了解 python 的工作原理,您就不會真正知道會發生什么。 你會遇到同樣的問題int s 或float s。 其他答案很好地解釋了“幕后”的東西(字符串實習),但您在日常編程中通常不必擔心它。

請注意,這是 CPython 特定的優化。 如果你希望你的代碼是可移植的,你應該避免它。 例如,在 PyPy

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

還值得指出的是,對於小整數也會發生類似的事情

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

您不應該再依賴它,因為其他實現可能不包括此優化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM