2017-06-16 26 views
10

Giả sử tôi có hai đối tượng của cùng một lớp: objA và objB. Mối quan hệ của họ là như sau:Tôi có thể thay đổi cách thức so sánh các phím trong một Python dict? Tôi muốn sử dụng toán tử 'is' thay vì ==

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

Nếu tôi sử dụng cả hai đối tượng làm khóa trong Python, thì chúng sẽ được coi là khóa giống nhau và ghi đè lên nhau. Có cách nào để ghi đè lên bộ so sánh dict để sử dụng so sánh is thay vì == sao cho hai đối tượng đó sẽ được xem là các khóa khác nhau trong dict?

Có lẽ tôi có thể ghi đè phương thức bằng trong lớp học hay gì đó? Để cụ thể hơn, tôi đang nói về hai đối tượng Tag từ thư viện BeautifulSoup4.

Dưới đây là một ví dụ cụ thể hơn về những gì tôi đang nói về:

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

Vui lòng cung cấp sản lượng dự kiến ​​với ví dụ vì những gì bạn đang yêu cầu không phải là điều chung chung. –

+2

Bạn không thể ghi đè phương thức bằng của đối tượng? – Carcigenicate

+2

Theo ý kiến ​​của tôi, thay vì cố gắng để ghi đè lên lớp dict, bạn có thể có thể ghi đè lên phương thức bình đẳng của đối tượng, hoặc thậm chí cung cấp một wrapper cho đối tượng nếu cần thiết. – Ding

Trả lời

8

first_h1second_h1Tag class trường. Khi bạn làm my_dict[first_h1] hoặc my_dict[second_h1], biểu diễn chuỗi của các thẻ được sử dụng để băm. Vấn đề là, cả hai Tag trường hợp có cơ quan đại diện chuỗi giống nhau:

<h1>some_header</h1> 

này được vì Tag lớp đã __hash__() magic method định nghĩa như sau:

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

Một trong những cách giải quyết có thể được sử dụng các giá trị id() dưới dạng băm, nhưng có vấn đề khi xác định lại các lớp Tag bên trong chính nó là BeautifulSoup. Bạn có thể workaround rằng vấn đề bằng cách làm riêng tùy chỉnh "tag wrapper" của bạn:

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) 

Sau đó, bạn sẽ có thể làm:

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} 

Đó là, tuy nhiên, không đẹp và không phải là khá thuận tiện để sử dụng. Tôi sẽ nhắc lại vấn đề ban đầu của bạn và kiểm tra xem bạn có thực sự cần phải đưa thẻ vào từ điển hay không.

Bạn cũng có thể vá khỉ bs4 bằng cách sử dụng các quyền hạn nội tại của Python, như it was done here, nhưng điều này sẽ đi vào một lãnh thổ khá nguy hiểm.

+1

Bạn đang thiếu phương thức __eq__ trong lớp trình bao bọc như sau: def __eq __ (tự, khác): id trả về (self.tag) Nhưng dù sao, tôi nhận được mã của tôi hoạt động vì câu trả lời của bạn! –

2

Có vẻ như bạn muốn ghi đè lên các nhà điều hành ==, bạn có thể chọn tùy chọn xây dựng một lớp mới và thực hiện các hành ==:

def __eq__(self, obj) : 
     return (self is obj) 
Các vấn đề liên quan