假设我有两个属于同一类的对象:objA 和 objB。它们的关系如下:
(objA == objB) #true (objA is objB) #false
如果我将两个对象都用作 Python 字典中的键,那么它们将被视为同一个键,并相互覆盖。有没有办法覆盖字典比较器以使用比较is而不是,==这样两个对象将被视为字典中的不同键?
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'.
Pythondict使用__eq__和__hash__方法来确定键的唯一性。由于first_h1 == second_h1计算结果为True,因此它们的哈希值相同,因此字典将它们视为相同的键。
dict
__eq__
__hash__
first_h1 == second_h1
True
要将和my_dict视为不同的键,您可以:first_h1``second_h1
my_dict
first_h1``second_h1
以下是使用每种方法可以实现此目的的方法:
使用id(obj)确保每个对象都被视为唯一的:
id(obj)
my_dict = {id(first_h1): 1, id(second_h1): 2} print(len(my_dict)) # This will print 2
要访问原始对象,可以将它们与其 ID 一起存储:
id_to_tag = {id(first_h1): first_h1, id(second_h1): second_h1}
如果您需要更灵活的解决方案,可以定义一个使用以下命令比较键的字典子类is:
class IdentityDict(dict): def __setitem__(self, key, value): super().__setitem__(id(key), (key, value)) def __getitem__(self, key): return super().__getitem__(id(key))[1] def __contains__(self, key): return id(key) in self def items(self): return ((kv[0], kv[1]) for kv in super().values()) # Usage my_dict = IdentityDict() my_dict[first_h1] = 1 my_dict[second_h1] = 2 print(len(my_dict)) # This will print 2
在IdentityDict、__setitem__、__getitem__和 中,__contains__所有操作都使用id(key),它强制使用身份比较 ( is) 而不是相等性比较 ( ==),因此每个对象都被视为唯一的。
IdentityDict
__setitem__
__getitem__
__contains__
id(key)