Python 字符串输入的 switch 有什么好的替代方法?

What's a good alternative to switch for Python string inputs?

我正在抓取一系列网页并将它们的内容组织到一个 in-memory 知识库中。我需要根据我的字符串输入执行不同的代码,这是从网站的标题中抓取的。

tags = browser.find_elements_by_xpath("//div[@class='main-content-entry']/h2")
for tag in tags:
  heading = tag.get_attribute("textContent").lower().strip()
  content = tag.parent
  if heading.find("overview") != -1:
    # do this
  elif heading.find("takeaways") != -1:
    # do that
  # do more elifs
  else:
    # do something else

现在,我将其实现为 if-elif-else 语句。我在网站上看到了建议使用字典的答案,但据我所知,这取决于输入是否与密钥完全匹配。然而,就我而言,由于网站所有者的不一致,并不总是能够完全匹配。

页面的结构足够我知道标题名称是什么,所以我可以在我的代码中提前定义 "keys"。但是,某些 hundred-over 页面中的某些标题存在拼写错误和轻微变体。例如:

我目前所能做的最好的事情是首先扫描页面,识别整组标题,然后手动定义要在我的代码中使用的子字符串,以避免重复。

考虑到上述情况,是否有更好的方法来迭代执行链式 if-elif-else 语句?

编辑

Replacements for switch statement in Python? 中的建议答案不适用于我的情况。举个例子:

def do_this(heading):
  return {
    "overview": do_overview(),
    "fees": do_fees(),
    # ...
  }[heading]

这将是该问题的答案所建议的实施方式。但是,当 heading"fees & funding""fees""fees &funding" 等时,我如何 return do_fees() 等等?如果键值是 heading.

的子字符串,我需要执行正确的函数

Considering the above, is there a better way then to iteratively execute a chained if-elif-else statement?

您无需使用特定键直接从字典中查找值。您可以只使用字典来压缩您的解析逻辑:

def extract_overview(content):
    ...

def extract_takeaways(content):
    ...

EXTRACTORS = {
    'overview': extract_overview,
    'takeaways': extract_takeaways,
    ...
}

for tag in tags:
    heading = tag.get_attribute("textContent").lower().strip()
    content = tag.parent

    for substring, function in EXTRACTORS.items():
        if substring in heading:
            result = function(content)
            break
    else:
        # No extractor was found

如果您想要匹配 typo-ed 个字符串,那么对于您的某些输入,您将需要某种模糊匹配。然而,对于那些结构良好的语句,您可以通过调整字典方法来获得 switch 语句的线性时间优势。 (这仅在您有很多案例时才重要)。

funcs = {
    "certificates": lambda: "certificates",
    "fees": lambda: "fees",
}

headings =['Fees & Funding', 'Fees', 'Fees &Funding', 'Certificates',
           'Certificate', 'Certificat & Exams', 'Exams & Certificates']

def do_this(heading):
    words = heading.lower().split()
    funcs_to_call = [funcs[word] for word in words if word in funcs]
    if len(funcs_to_call) == 1:
        return funcs_to_call[0]()
    elif len(funcs_to_call) == 0:
        return 'needs fuzzy matching'
    else:
        #alternatively treat it as being in multiple categories.
        raise ValueError("This fits more than one category")


for heading in headings:
    print(heading, parse(heading), sep = ': ')
#outputs:
Fees & Funding: fees
Fees: fees
Fees &Funding: fees
Certificates: certificates
Certificate: needs fuzzy matching
Certificat & Exams: needs fuzzy matching
Exams & Certificates: certificates

如果您能够预测您将要面对的拼写错误类型,您可以更早地清理字符串以获得更准确的匹配,例如删除符号和使单词复数。