python - 我可以更改 Python 字典中键的比较方式吗?我想使用运算符 'is' 而不是 ==

标签 python dictionary beautifulsoup equals

假设我有两个属于同一类的对象:objA 和 objB。它们的关系如下:

(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'.

最佳答案

first_h1second_h1 Tag 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 的内省(introspection)功能对 bs4 进行猴子修补,例如 it was done here ,但这将进入一个相当危险的领域。

关于python - 我可以更改 Python 字典中键的比较方式吗?我想使用运算符 'is' 而不是 ==,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44595688/

相关文章:

Python MySQLdb TypeError : not all arguments converted during string formatting

python - 具有基于列名称的图例的 T-SNE 散点图

python - 无法在 Raspberry Pi 启动时执行 python 脚本

swift - 有没有办法遍历 Key :[Value1:[Value2]]? 形式的字典

python - Pandas,Wide_to_Long 正在创建额外的错误行和额外的错误列

c# - 以枚举为键绑定(bind)到字典中的值

用于排序元组的 Python 字典,可以做得更好吗?

python - 如何将嵌套在 div 下的所有 div 抓取到列表中?

python - 如何在每日时间序列对象上迭代网络抓取脚本,以便从网页创建每日时间序列数据

ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式