2010-06-07 43 views
52

... is關鍵字可用於字符串中的相等性。如何在Python中實現'is'關鍵字?

>>> s = 'str' 
>>> s is 'str' 
True 
>>> s is 'st' 
False 

我都嘗試__is__()__eq__(),但他們沒有工作。

>>> class MyString: 
... def __init__(self): 
...  self.s = 'string' 
... def __is__(self, s): 
...  return self.s == s 
... 
>>> 
>>> 
>>> m = MyString() 
>>> m is 'ss' 
False 
>>> m is 'string' # <--- Expected to work 
False 
>>> 
>>> class MyString: 
... def __init__(self): 
...  self.s = 'string' 
... def __eq__(self, s): 
...  return self.s == s 
... 
>>> 
>>> m = MyString() 
>>> m is 'ss' 
False 
>>> m is 'string' # <--- Expected to work, but again failed 
False 
>>> 

回答

107

使用is測試字符串僅在字符串被攔截時纔有效。除非你真的知道自己在做什麼,並明確表示interned字符串,你應該從來沒有在字符串上使用is

is測試身份而不是等於。這意味着Python只是比較對象所在的內存地址。is基本上回答了這個問題:「我對同一個對象有兩個名字嗎?」 - 超載,這是沒有意義的。

例如,("a" * 100) is ("a" * 100)。通常Python將每個字符串寫入不同的內存位置,實習主要發生在字符串文字上。

+8

我已經在過去該字符串實習可能發生的計算運行時間和輸入值,如果他們足夠短的觀察。 'a'* 100不是'a'* 100;但'a'* 20是「a」* 20.與此同時'a'.upper()不是'a'.upper()。 Jython,IronPython,PyPy和其他人可能會更積極地實習。 簡而言之,它取決於實現。正如你所說,在字符串中調用'intern()'函數將「強制」一個字符串與任何等價的和以前的intern()'字符串具有相同的對象標識。但是,我不知道測試字符串標識的有效用例。 (可能的表現)。 – 2010-06-08 09:16:55

8

is關鍵字比較對象(或者,相反,如果兩個引用是對同一對象進行比較)。

這是,我想,爲什麼沒有機制來提供自己的實現。

它偶爾會在字符串上工作,因爲Python'聰明地'存儲字符串,這樣當你創建兩個相同的字符串時,它們被存儲在一個對象中。

>>> a = "string" 
>>> b = "string" 
>>> a is b 
True 
>>> c = "str"+"ing" 
>>> a is c 
True 

可以希望看到基準VS在一個簡單的「複製」的示例數據比較:

>>> a = {"a":1} 
>>> b = a 
>>> c = a.copy() 
>>> a is b 
True 
>>> a is c 
False 
17

is的操作等同於比較id(x)值。目前使用id來使用指針作爲比較。所以你不能超載is本身,而AFAIK你也不能超載id

所以,你不能。在python中是不尋常的,但在那裏。

+1

你可以重載'id',但不是你的意思。只要做'id = '。 – HyperNeutrino 2017-02-28 15:00:31

13

Python is關鍵字測試對象標識。你不應該用它來測試字符串相等。它似乎經常工作,因爲像許多高級語言的Python實現一樣,執行字符串的「interning」。也就是說,字符串文字和值在內部保存在哈希列表中,而那些相同的文字和值被渲染爲對同一對象的引用。 (這是可能的,因爲Python字符串是不可變的)。

但是,與任何實現細節一樣,您不應該依賴於此。如果你想測試平等使用==運算符。如果你真的想測試對象的身份,然後使用is ---我很難想出一個案例,你應該關心字符串對象的身份。不幸的是,你不能指望兩個字符串是否由於上述實習而以某種方式「故意」相同的對象引用。

+0

Python中您想要進行身份比較的唯一地方是比較單身人士(例如無)和需要唯一的哨兵值。除此之外,可能幾乎沒有理由。 – 2010-06-08 07:17:06

+2

@賴瑞安:我傾向於同意。我只用它用於None和我創建的特殊哨兵(通常是調用基礎對象())。然而,我不覺得聲稱'is'操作符沒有其他有效的用法;只是沒有我能想到的。 (可能是我自己無知的證明)。 – 2010-06-08 09:03:14

5

如果你不怕搞亂字節碼,你可以攔截並修補COMPARE_OP8 ("is")參數來調用你的鉤子函數在被比較的對象上。請參閱dis模塊文檔以瞭解入門。

如果有人會做id(a) == id(b)而不是a is b,也不要忘記攔截__builtin__.id()

+1

有趣的是,這是一個混淆我從未想過的python函數的可能性的整個世界。但爲什麼這是一個好主意? – alexis 2014-05-20 14:49:04

+0

在我的公司,我們有一個內部測試庫,其中包含一個上下文裝飾器,它通過將實例始終從utcnow()返回特定時間的實現替換datetime.datetime來凍結時間。 如果您運行datetime.datetime.utcnow()並試圖醃製返回的值,它將失敗,因爲它的類不一致(它假裝是另一個類)。在這種情況下,覆蓋「正在」工作的方式可能是一個解決方案。 – 2016-04-01 20:36:40

2

無法將字符串變量與字符串值和兩個字符串變量進行比較,當字符串以' - '開頭時。我的Python版本是2.6.6

>>> s = '-hi' 
>>> s is '-hi' 
False 
>>> s = '-hi' 
>>> k = '-hi' 
>>> s is k 
False 
>>> '-hi' is '-hi' 
True 
1

您不能超載is運算符。您想要超載的是==運營商。這可以通過在類中定義__eq__方法來完成。

1

您正在使用標識比較。 ==可能是你想要的。這是一個例外,當你想要檢查一個項目和另一個項目是否是相同的EXACT對象並處於相同的內存位置時。在你的例子中,這個項目是不一樣的,因爲一個是不同的類型(my_string)而不是另一個(字符串)。另外,沒有某個類別的東西。 python中的__is__(除非你自己把它放在那裏)。如果有的話,與比較對象是對於簡單地比較內存位置將不可靠。

當我第一次遇到關鍵字時,它也讓我困惑。我會認爲和==沒有什麼不同。他們在許多對象上爲解釋器提供了相同的輸出。這種假設實際上完全是 ...。這是python的等價物,「嘿,不要把這兩個物體弄錯,它們是不同的。」這本質上是什麼[無論是誰讓我挺直]說。有很大不同,但有一點==另一點。

的 一些有用的例子和一些文字,以幫助有時混亂的差異 訪問a document from python.org's mail host由「丹尼柳」

,或者書面如果這是離線,請我把它的身體unlisted pastebin

的情況下,他們在大約20個左右的藍月(藍月是一個真實的事件),都下來了,我會引用代碼示例

### 
>>> my_name = "danny" 
>>> your_name = "ian" 
>>> my_name == your_name 
0    #or False 
### 

### 
>>> my_name[1:3] == your_name[1:3] 
1 #or True 
### 

### 
>>> my_name[1:3] is your_name[1:3] 
0 
### 
0

的斷言錯誤可以很容易地是出現比較對象時的關鍵字。例如,對象ab可能保持相同的值並共享相同的存儲器地址。因此,做一個

>>> a == b 

是要評估對

True 

但如果

>>> a is b 

評估爲

False 

你應該檢查

>>> type(a) 

>>> type(b) 

這些可能是不同的,對於失敗的原因。

1

'is'比較對象標識,而==比較值。

例子:

a=[1,2] 
b=[1,2] 
#a==b returns True 
#a is b returns False 

p=q=[1,2] 
#p==q returns True 
#p is q returns True