2014-11-21 36 views
11

考慮以下代碼:'is'運算符爲什麼說這些方法不一樣?

class Person(object): 
    def sayHello(self): 
     return 'Hello' 

print(Person().sayHello is Person().sayHello) 

我希望它表現出真正的。它爲什麼顯示錯誤?

+1

看到這個問題http://stackoverflow.com/a/133024/1394473 – tom 2014-11-21 20:15:32

+4

@湯姆,雖然這並不能真正解釋比較實例方法 – davidism 2014-11-21 20:18:29

+0

@Test你爲什麼期望你的表達式爲真?你必須期待這兩個子表達式是同一個對象。是什麼導致你這個斷言? – quamrana 2014-11-21 21:20:29

回答

16

方法對在運行勢必實例。當您運行以下代碼時:

print(Person().sayHello is Person().sayHello) 

您創建兩個實例並且每次有不同的內存地址時。

>>> Person().sayHello 
<bound method Person.sayHello of <__main__.Person object at 0x7fbe90640410>> 
>>> Person().sayHello 
<bound method Person.sayHello of <__main__.Person object at 0x7fbe90640490>> 

注意:我們所有的Python都是運行時;有沒有這樣的事情作爲一個單獨的編譯時間

+10

[如果你有一個實例,你會*仍然*得到'False',因爲你在每次訪問時都會得到一個新的方法對象。](http://stackoverflow.com/questions/15977808/why-dont-methods -have-reference-equality) – user2357112 2014-11-22 01:35:44

+0

@ user2357112是的,當然。 – Kasramvd 2014-11-22 06:08:52

+4

*在python *中是單獨的編譯時間。例如,名稱範圍在編譯時確定。各種文字變成常數,並在編譯時應用窺視孔優化。這裏不適用,但不要求它不存在。 – 2014-11-25 08:04:23

0

這將是True如果你叫sayHello

print(Person().sayHello() is Person().sayHello()) 

在你的代碼實際上是比較上的對象的方法,並檢查它們是否具有相同的身份(他們沒有)。另外要注意的區別:

"Hello" is "Hello" 

"Hello" == "Hello" 

在第一個,你要比較的對象的身份(這是由於相同的字符串被重用,調用id("Hello")多次看到這一點)。第二,你比較字符串的內容以查看它們是否相等(即,具有相同的字符)。現在,相同的字符串也會有相同的標識,但我不確定這個假設是否適用於所有Python實現。

+0

它是一樣的「你好」是「你好」,我相信他想比較功能而不是結果 – Andres 2014-11-21 20:13:29

+0

@Test:在我的機器上是'False'...? – 2014-11-21 20:13:45

+3

@SimeonVisser Python的一些實現會記憶短字符串 – 2014-11-21 20:14:57

5

我會假設你是有意比較方法對象本身,而不是你真的想比較輸出字符串,只是忘了()sayHello後。

試試這個實驗:

a = Person() 
b = Person() 

a.sayHello 
b.sayHello 

你會看到a.sayHello顯示爲類似

<bound method Person.sayHello of <__main__.Person instance at 0x102cc8ef0>> 

...而b.sayHello顯示器類似,但具有不同的父實例指針:

<bound method Person.sayHello of <__main__.Person instance at 0x102d31908>> 

的0一個實例的結合方法本身是一個不同實例(方法)從同一個名字的從不同的Person實例綁定的方法。你可以用id(a.sayHello)id(b.sayHello)來確認,它返回兩個綁定方法的標識哈希 - 它們將會不同。由於您的代碼Person().sayHello is Person().sayHello創建了兩個不同的Person實例,因此情況與我的命名實例示例ab相同。

+2

沒有關係,有不同的情況。即使只有一個實例,如果您訪問該方法兩次,您也會得到兩個不同的方法對象。 – 2014-11-25 07:54:50

+0

好點。 'a.sayHello'中隱含的'getattr'操作是每次你創建一個新的綁定方法實例。對於我來說,這被一個事實掩蓋了(可能取決於平臺/實現),如果你說'id(a.sayHello)'兩次,你會得到相同的id號碼兩次。但是如果你不讓第一個方法實例超出範圍,你會得到*不同的* id號。所以'as1 = a.sayHello; as2 = a.sayHello; print([id(as1),id(as2)])'給了我不同的數字,而'print([id(a.sayHello),id(a.sayHello)])'給了我相同的數字。 – jez 2014-11-25 19:02:28

+0

如果對象已被刪除,'id()'值可以重用。總是先創建一個對象,然後再測試。 – 2014-11-25 19:25:47

6

它們是同一類的兩個不同實例。 sayHello函數是綁定方法

也就是說,如果你有一個類的實例:

p = Person() 

,你就可以查找一個屬性:

p.sayHello 

那麼Python首先着眼於實例的實際屬性,如果它沒有找到那裏的屬性,它看着這個類。 如果它找到該名稱的類方法,它會將其變成綁定方法,綁定到此實例。這是導致對象實例作爲第一個參數(self)傳遞到sayHello的魔法。

因此Person().sayHello is Person().sayHello創建兩個實例,根據類上定義的相同方法創建兩個不同的綁定方法,因此is返回False,因爲它們是不同的方法。

+2

即使在相同的實例中,每次訪問它們時都會重新創建方法。無所謂這裏有兩個傳出實例。 – 2014-11-25 07:53:39

-1

如果你想它返回一個表達式True你可以試試這個:

print(Person.sayHello is Person.sayHello) 

只是爲了增加混亂,執行:

>>> say = Person.sayHello 
>>> say() 
Traceback (most recent call last): 
    File "<pyshell#5>", line 1, in <module> 
    say() 
TypeError: sayHello() missing 1 required positional argument: 'self' 

,甚至:

>>> say(say) 
'Hello' 
>>> say(None) 
'Hello' 
>>> 

這是因爲:

>>> say 
<function Person.sayHello at 0x02AF04B0> 

say指的是Person.sayHello這是一個函數,可以調用,但需要一個參數,但在這種情況下參數是不相關的。現在

,如果你不想讓供應無用的參數,你可以有一個自動綁定:

>>> p=Person() 
>>> p.sayHello() 
'Hello' 
+4

是的,但有很多表達式可以打印True,就像'print(True)'。 OP的問題是爲什麼方法似乎有身份危機。 – tdelaney 2014-11-21 21:15:03

+1

在Python 2中,返回未綁定方法的情況下仍會失敗。 – 2014-11-25 07:56:42

相關問題