当前位置: 首页 > 知识库问答 >
问题:

如何使用结构模式匹配检测可散列类型?

齐望
2023-03-14

使用结构模式匹配,如何编写匹配哈希类型实例的案例?

我尝试过:

for obj in [], (), set(), frozenset(), 10, None, dict():
    match obj:
        case object(__hash__=_):
            print('Hashable type:  ', type(obj))
        case _:
            print('Unhashable type: ', type(obj))

但是,这得到了错误的答案,因为每个类型都定义了它是否可哈希:

Hashable type:   <class 'list'>
Hashable type:   <class 'tuple'>
Hashable type:   <class 'set'>
Hashable type:   <class 'frozenset'>
Hashable type:   <class 'int'>
Hashable type:   <class 'NoneType'>
Hashable type:   <class 'dict'>

共有2个答案

安聪
2023-03-14

集合中的可哈希抽象基类。abc可以通过测试识别实现哈希的类型,如isinstance(obj,Hashable)或issubclass(cls,Hashable)。

根据PEP 622,对于类模式,“匹配是否成功由is实例调用的等价物决定。”

因此,您可以直接在类模式中使用Hasable:

from collections.abc import Hashable

for obj in [], (), set(), frozenset(), 10, None, dict():
    match obj:
        case Hashable():
            print('Hashable type:  ', type(obj))
        case _:
            print('Unhashable type:', type(obj))

这将生成所需的答案:

Unhashable type: <class 'list'>
Hashable type:   <class 'tuple'>
Unhashable type: <class 'set'>
Hashable type:   <class 'frozenset'>
Hashable type:   <class 'int'>
Hashable type:   <class 'NoneType'>
Unhashable type: <class 'dict'>

Hashable只处理最外层对象的类型。它报告了“对象类型实现哈希”意义上的哈希性,这就是我们通常所说的“元组是可哈希的”。这也是抽象基类和静态类型使用的相同含义。

尽管哈希可检测类型是否实现了_hash_,但它无法知道哈希实际做了什么,是否会成功,或者是否会给出一致的结果。

例如,散列给出了浮动('NaN')的不一致结果。元组和frozenset通常是可散列的,但如果它们的组件值不可散列,则无法散列。一个类可以定义__hash__以始终引发异常。

蒲昀
2023-03-14

RaymondHettinger的答案在有限的情况下有效,但它在诸如<代码>列表 (类型对象本身)之类的输入上失败,即使是<代码>列表,它也是可散列的__hash\uuuuu是None(无),输入类似于([1,2],[3,4]),即使是tuple(元组),也是不可损坏的__hash\uuuu不是None。

检测对象是否可散列的最可靠方法总是尝试散列它。如果您想在匹配语句中执行此操作,最简单的方法是编写一个保护:

def hashable(x):
    try:
        hash(x)
    except TypeError:
        return False
    else:
        return True

match x:
    case _ if hashable(x):
        ...
    ...

这只是直接调用hash(x)并查看它是否工作,而不是尝试执行结构检查。

如果您需要哈希并希望避免双重计算,您可以保存hash(x)结果:

def try_hash(x):
    try:
        return hash(x)
    except TypeError:
        return None

match x:
    case _ if (x_hash := try_hash(x)) is not None:
        ...
    ...
 类似资料:
  • 我一直在将if-elif链转换为结构模式匹配,但在反向测试中遇到了困难。 很容易生成与任何支持的模式(文本、类、映射、序列等)匹配的案例。我如何证明一个否定的匹配? 例如,当对象的类型不匹配时,我需要强制它:

  • 我无法运行此代码: 我在Python中找不到匹配关键字。 我在这里找到的:https://www.python.org/dev/peps/pep-0622/#the-match语句 有什么想法吗?

  • 模式有两种形式:refutable(可反驳的)和 irrefutable(不可反驳的)。能匹配任何传递的可能值的模式被称为是 不可反驳的(irrefutable)。一个例子就是 语句中的 x,因为 x 可以匹配任何值所以不可能会失败。对某些可能的值进行匹配会失败的模式被称为是 可反驳的(refutable)。一个这样的例子便是 if let Some(x) = a_value 表达式中的 Some

  • 我有一个字符串,我正试图根据几个regex模式验证它,我希望由于模式匹配在3.10中可用,我可以使用它来代替创建if-else块。 考虑一个字符串'validateString',其可能的值1021102,1.25.32string021。 我尝试的代码如下所示。 对于正则表达式1、2和3,我尝试了字符串正则表达式模式,还重新设置了。编译对象,但它似乎不起作用。 我一直试图在互联网上找到这方面的例

  • 我有通过查找属性来检查命名元组和数据类的代码: 如何使用Python 3.10的匹配/大小写结构模式匹配来表达这一点?