2017-06-16 4 views
10

の代わりに演算子 'is'を使用したいと思いましょう。同じクラスの2つのオブジェクトobjAとobjBがあります。彼らの関係は以下の通りです:私はPythonの辞書のキーとして両方のオブジェクトを使用する場合はPython dictでキーの比較方法を変更できますか? ==

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

、それらは同じ鍵であると考え、お互いに上書きされます。 dictコンパイラを==の代わりにisの比較を使用するようにオーバーライドする方法はありますか?そのため、2つのオブジェクトはdictの別のキーと見なされますか?

多分私はクラスまたは何かのequalsメソッドをオーバーライドできますか?具体的には、BeautifulSoup4ライブラリの2つの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

私の意見では、dictクラスをオーバーライドしようとするのではなく、オブジェクトのequalメソッドをオーバーライドしたり、必要であればオブジェクトのラッパーを提供することもできます。 – Ding

答えて

8

first_h1second_h1Tag classインスタンスです。 my_dict[first_h1]またはmy_dict[second_h1]を実行すると、文字表記のタグがハッシュに使用されます。次のように

<h1>some_header</h1> 

これはTagクラスは__hash__()魔法のメソッドが定義されていているので、::回避策の

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

一つは使用することができ、問題は、これらのTagインスタンスの両方が同じ文字列表現を持っている、です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} 

それは、しかし、きれいではありませんし、非常に便利ではありません使用する。私はあなたの最初の問題を繰り返し述べ、実際にタグを辞書に入れる必要があるかどうかを確認します。

it was done hereのようなPythonのイントロスペクションパワーを使用してmonkey-patch bs4を作成することもできますが、これはかなり危険な領域に入ることになります。

+1

ラッパークラスに__eq__メソッドがありません: def __eq __(self、other): return id(self.tag) しかし、とにかくおかげさまで、私はあなたの答えのために働いています! –

2

あなたがオペレータ==を上書きしたい、あなたは新しいクラスを構築するオプションを選択し、オペレータ==実装できそうです:

def __eq__(self, obj) : 
     return (self is obj) 
関連する問題