2012-03-23 55 views
14

您有一個需要進行等值測試的Python類。 Python應該使用duck-typing,但是它是(更好還是更準確)在eq函數中包含或排除isinstance測試?例如:如果在Python中輸入鴨子,你應該測試isinstance嗎?

class Trout(object): 
    def __init__(self, value): 
     self.value = value 

    def __eq__(self, other): 
     return isinstance(other, Trout) and self.value == other.value 
+1

我認爲這是'isinstance'的合法用例。 – 2012-03-23 17:15:48

回答

11

__eq__中使用isinstance方法很常見。原因是如果__eq__方法失敗,它可以從另一個對象回退__eq__方法。大多數普通方法都是明確調用的,但__eq__是隱式調用的,所以它需要更頻繁地查看。

編輯(感謝您的提醒,斯文Marnach):

爲了使它回退,您可以返回NotImplemented單,如本例:

class Trout(object): 
    def __init__(self, value): 
     self.value = value 

    def __eq__(self, other): 
     if isinstance(other, Trout): 
      return self.value == other.value 
     else: 
      return NotImplemented 

假設一個RainbowTrout知道如何比較本身爲Trout或另一RainbowTrout,但Trout只知道如何比較自己與Trout。在本例中,如果您測試mytrout == myrainbowtrout,Python將首先調用mytrout.__eq__(myrainbowtrout),注意它失敗,然後調用myrainbowtrout.__eq__(mytrout),這會成功。

+0

雖然這個答案是真的,但它並沒有解釋如何以實際上有助於回退到其他對象的__eq __()'的方式實現'__eq __()'。 – 2012-03-23 17:59:47

+0

@SvenMarnach,好點。我會編輯。 – amcnabb 2012-03-23 18:01:58

4

「鴨子打字」的原則是你不在乎什麼other是,只要它具有value屬性。所以,除非你的屬性共享衝突的語義的名字,我會建議做這樣的:

def __eq__(self, other): 
    try: 
     return self.value == other.value 
    except AttributeError: 
     return False # or whatever 

(或者你可以測試other是否有value屬性,但「它更容易請求原諒比獲得許可」 )

+3

這可能會導致一些非常愚蠢的事情,比如'鱒魚(「彩虹」)== Lorikeet(「彩虹」)',即使幾乎沒有人會認爲魚與鳥類相等。 – SingleNegationElimination 2012-03-23 17:38:29

+1

@Token,在這種情況下,鴨子打字不適合你。順便說一下,如果它們在屬性「值」中存儲「彩虹」,它們只會相等。 – alexis 2012-03-23 22:01:31

+0

...並且您可以根據OP的需要定義他們的'__eq__'方法,只查看'value'字段。但是,是的,這是鴨子打字的原則。愛它或離開它。 – alexis 2012-03-23 22:19:35

6

使用isintsance()__eq__()方法中通常很好。你不應該立即返回False如果isinstance()檢查失敗,雖然 - 這是更好地回報NotImplementedother.__eq__()被執行的機會:

def __eq__(self, other): 
    if isinstance(other, Trout): 
     return self.x == other.x 
    return NotImplemented 

這將成爲在類層次結構在多於一個尤爲重要類定義__eq__()

class A(object): 
    def __init__(self, x): 
     self.x = x 
    def __eq__(self, other): 
     if isinstance(other, A): 
      return self.x == other.x 
     return NotImplemented 
class B(A): 
    def __init__(self, x, y): 
     A.__init__(self, x) 
     self.y = y 
    def __eq__(self, other): 
     if isinstance(other, B): 
      return self.x, self.y == other.x, other.y 
     return NotImplemented 

如果您想立即返回False,正如你在原來的代碼一樣,你會失去A(3) == B(3, 4)B(3, 4) == A(3)之間的對稱。

相關問題