我可以更改 Python 字典中键的比较方式吗?我想使用运算符 'is' 而不是 ==
Can I change the way keys are compared in a Python dict? I want to use the operator 'is' instead of ==
假设我有两个对象 class:objA 和 objB。他们的关系如下:
(objA == objB) #true
(objA is objB) #false
如果我将两个对象都用作 Python 字典中的键,那么它们将被视为相同的键,并相互覆盖。有没有办法覆盖字典比较器以使用 is
比较而不是 ==
以便这两个对象将被视为字典中的不同键?
也许我可以重写 class 中的 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'.
您似乎想覆盖运算符 ==
,您可以选择构建新 class 的选项并实施运算符 ==
:
def __eq__(self, obj) :
return (self is obj)
first_h1
和 second_h1
是 Tag
class 个实例 。当您执行 my_dict[first_h1]
或 my_dict[second_h1]
时,标签的 字符串表示形式 用于散列。问题是,这两个 Tag
实例都具有相同的字符串表示形式:
<h1>some_header</h1>
这是因为Tag
class有__hash__()
魔术方法定义如下:
def __hash__(self):
return str(self).__hash__()
其中一个解决方法是使用 id()
值作为散列,但是在 BeautifulSoup
本身内部重新定义 Tag
classes 存在问题.您可以通过自定义 "tag wrapper":
来解决该问题
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 的自省能力来猴子修补 bs4
,比如 ,但这将进入一个相当危险的领域。
假设我有两个对象 class:objA 和 objB。他们的关系如下:
(objA == objB) #true
(objA is objB) #false
如果我将两个对象都用作 Python 字典中的键,那么它们将被视为相同的键,并相互覆盖。有没有办法覆盖字典比较器以使用 is
比较而不是 ==
以便这两个对象将被视为字典中的不同键?
也许我可以重写 class 中的 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'.
您似乎想覆盖运算符 ==
,您可以选择构建新 class 的选项并实施运算符 ==
:
def __eq__(self, obj) :
return (self is obj)
first_h1
和 second_h1
是 Tag
class 个实例 。当您执行 my_dict[first_h1]
或 my_dict[second_h1]
时,标签的 字符串表示形式 用于散列。问题是,这两个 Tag
实例都具有相同的字符串表示形式:
<h1>some_header</h1>
这是因为Tag
class有__hash__()
魔术方法定义如下:
def __hash__(self):
return str(self).__hash__()
其中一个解决方法是使用 id()
值作为散列,但是在 BeautifulSoup
本身内部重新定义 Tag
classes 存在问题.您可以通过自定义 "tag wrapper":
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 的自省能力来猴子修补 bs4
,比如