我想使用 PEP 634 – 结构模式匹配 来匹配具有特定属性的
HtmlElement
。这些属性可通过 .attrib
属性访问,该属性返回 _Attrib
类的实例,IIUC 它具有使其成为 collections.abc.Mapping
的所有方法。
政治公众人物这样说:
要使映射模式成功,主题必须是映射,其中映射被定义为其类是以下之一:
- 继承自
的类collections.abc.Mapping
- 已注册为
的 Python 类collections.abc.Mapping
- ...
这就是我想要做的,但它不会打印
href
:
from collections.abc import Mapping
from lxml.html import HtmlElement, fromstring
el = fromstring('<a href="https://stackoverflow.com/">StackOverflow</a>')
Mapping.register(type(el.attrib)) # lxml.etree._Attrib
assert(isinstance(el.attrib, Mapping)) # It's True even before registering _Attrib.
match el:
case HtmlElement(tag='a', attrib={'href': href}):
print(href)
这匹配并打印
attrib
:
match el:
case HtmlElement(tag='a', attrib=Mapping() as attrib):
print(attrib)
这与预期不匹配:
match el:
case HtmlElement(tag='a', attrib=list() as attrib):
print(attrib)
我也尝试过这个,它有效:
class Upperer:
def __getitem__(self, key): return key.upper()
def __len__(self): return 1
def get(self, key, default): return self[key]
Mapping.register(Upperer) # It doesn't work without this line.
match Upperer():
case {'href': href}:
print(href) # Prints "HREF"
我知道使用 XPath/CSS 选择器会更容易,但此时我只想知道
_Attrib
类和我的代码有什么问题。
另外,我不想解压元素并将
_Attrib
实例转换为 dict,如下所示:
match el.tag, dict(el.attrib):
case 'a', {'href': href}:
print(href)
或使用防护装置:
match el:
case HtmlElement(tag='a', attrib=attrs) if 'href' in attrs:
print(attrs['href'])
它可以工作,但看起来不正确。我想找到一个解决方案,以便原来的
case HtmlElement(tag='a', attrib={'href': href})
能够工作。或者非常接近它的东西。
我使用的Python版本是3.11.4。
Python 使用
match case
来比较两个对象是否相等似乎存在问题,因为使用 match case 语句的模式匹配通常用于匹配不同的值,而不是比较对象是否相等。在Python中,==
运算符经常用于比较对象是否相等。如果要比较两个对象是否相等,应使用 ==
而不是 match case
。
写一个类进行比较:
class Element:
def __init__(self,data : HtmlElement= None,**kwargs):
if not kwargs:
temp={'tag': data.tag, 'text': data.text,'tail': data.tail,'attrib': data.attrib}
self.__dict__ = {i:temp[i] for i in temp if temp[i]}
return
self.__dict__ =kwargs
def __eq__(self, other):
return self.__dict__ == other.__dict__
使用if语句判断是否相等
if Element(el) == Element(tag='a',text= 'StackOverflow', attrib={'href': 'https://stackoverflow.com/'}):
print('equal')