2017-06-16 56 views
10

假設我有兩個同一類的對象:objA和objB。他們的關係是這樣的:我可以在Python字典中更改鍵的對比方式嗎?我想使用運算符'is'而不是==

(objA == objB) #true 
(objA is objB) #false 

如果我使用這兩個對象在Python字典鍵,那麼他們將被視爲相同的密鑰,並且相互覆蓋。有沒有辦法來覆蓋字典比較器使用is而不是==比較,以便這兩個對象將被視爲字典中的不同鍵?

也許我可以重寫類中的equals方法或什麼?更具體地說,我正在討論BeautifulSoup4庫中的兩個Tag對象。

下面是我在說什麼更具體的例子:你要重寫操作==

from bs4 import BeautifulSoup 

HTML_string = "<html><h1>some_header</h1><h1>some_header</h1></html>" 

HTML_soup = BeautifulSoup(HTML_string, 'lxml') 

first_h1 = HTML_soup.find_all('h1')[0]  #first_h1 = <h1>some_header</h1> 
second_h1 = HTML_soup.find_all('h1')[1]  #second_h1 = <h1>some_header</h1> 

print(first_h1 == second_h1)  # this prints True 
print(first_h1 is second_h1)  # this prints False 

my_dict = {} 
my_dict[first_h1] = 1 
my_dict[second_h1] = 1 

print(len(my_dict))     # my dict has only 1 entry! 

# I want to have 2 entries in my_dict: one for key 'first_h1', one for key 'second_h1'. 
+0

請用例子提供預期的輸出,因爲你所要求的不是一般的東西。 –

+2

你不能重寫對象本身的equals方法嗎? – Carcigenicate

+2

在我看來,你可能會重寫對象的平等方法,或者甚至爲對象提供一個包裝器(如果有必要的話),而不是試圖重寫字典類。 – Ding

回答

8

first_h1second_h1Tag class實例。當你做my_dict[first_h1]my_dict[second_h1],字符串表示的標籤用於哈希。問題是,這兩個Tag實例具有相同的字符串表示:

<h1>some_header</h1> 

這是因爲Tag類定義__hash__()魔術方法如下:

def __hash__(self): 
    return str(self).__hash__() 

其中一個解決方法可以是使用id()值作爲散列值,但在BeautifulSoup本身內部重新定義Tag類存在問題。您可以解決辦法通過使自己的自定義「標籤包裝」這一問題:

class TagWrapper: 
    def __init__(self, tag): 
     self.tag = tag 

    def __hash__(self): 
     return id(self.tag) 

    def __str__(self): 
     return str(self.tag) 

    def __repr__(self): 
     return str(self.tag) 

然後,你就可以做到:

In [1]: from bs4 import BeautifulSoup 
    ...: 

In [2]: class TagWrapper: 
    ...:  def __init__(self, tag): 
    ...:   self.tag = tag 
    ...: 
    ...:  def __hash__(self): 
    ...:   return id(self.tag) 
    ...: 
    ...:  def __str__(self): 
    ...:   return str(self.tag) 
    ...: 
    ...:  def __repr__(self): 
    ...:   return str(self.tag) 
    ...:  

In [3]: HTML_string = "<html><h1>some_header</h1><h1>some_header</h1></html>" 
    ...: 
    ...: HTML_soup = BeautifulSoup(HTML_string, 'lxml') 
    ...: 

In [4]: first_h1 = HTML_soup.find_all('h1')[0]  #first_h1 = <h1>some_header</h1> 
    ...: second_h1 = HTML_soup.find_all('h1')[1]  #second_h1 = <h1>some_header</h1> 
    ...: 

In [5]: my_dict = {} 
    ...: my_dict[TagWrapper(first_h1)] = 1 
    ...: my_dict[TagWrapper(second_h1)] = 1 
    ...: 
    ...: print(my_dict) 
    ...: 
{<h1>some_header</h1>: 1, <h1>some_header</h1>: 1} 

是,雖然不漂亮,不是很方便使用。我會重申你最初的問題,並檢查你是否真的需要將標籤放入字典中。

您也可以使用Python的內省權限(例如it was done here)來猴子補丁bs4,但這將會進入一個相當危險的領域。

+1

您在包裝類中缺少__eq__方法,如下所示: def __eq __(self,other): return id(self.tag) 但是,無論如何,我的代碼因爲您的答案而工作! –

2

看來,你可以選擇建立一個新的類的選項,並執行操作==

def __eq__(self, obj) : 
     return (self is obj) 
相關問題