在不容易实例化类的情况下,我们如何使用Python的 struct 模式匹配(在Python 3.10中引入)来匹配变量的类型,而不调用构造函数/?

以下代码失败:

from pydantic import BaseModel

# instantiation requires 'name' to be defined
class Tree(BaseModel):
    name: str

my_plant = Tree(name='oak')


match type(my_plant):
    case Tree:
        print('My plant is a tree.')
    case _:
        print('error')

错误消息为SyntaxError: name capture 'Tree' makes remaining patterns unreachable

另一种try 是在匹配期间重新创建实例(因为在匹配期间实例化很危险,但值得一试...)-它也失败了:

match type(my_plant):
    case type(Tree()):
        print('My plant is a tree.')
    case _:
        print('error')

TypeError: type() accepts 0 positional sub-patterns (1 given)

判断Tree()的实例可以解决SyntaxError,但不会导致工作输出,因为它总是产生"error".我不想使用变通方法来匹配派生的bool(例如,type(my_plant) == Tree))因为它会限制我只比较2个结果(True/False),而不是与多个类类型匹配.

推荐答案

继续我在 comments 中所说的:match引入一个值,而case引入一个要匹配的模式.它不是要计算的表达式.如果模式表示一个类,则括号中的内容不会传递给构造函数,而是与值为match的属性进行匹配.下面是一个说明性的例子:

class Tree:
    def __init__(self, name):
        self.kind = name
    
def what_is(t):
    match t:
        case Tree(kind="oak"):
            return "oak"
        case Tree():
            return "tree"
        case _:
            return "shrug"

print(what_is(Tree(name="oak")))    # oak
print(what_is(Tree(name="birch")))  # tree
print(what_is(17))                  # shrug

注意,在case之外,Tree(kind="oak")将是一个错误:

TypeError: Tree.__init__() got an unexpected keyword argument 'kind'

相反,case Tree(name="oak")永远不会匹配,因为我的示例中的Tree个实例通常没有名为name的属性.

这证明了case不会调用构造函数,即使它看起来像一个实例化.


编辑:关于你的第二个错误:你写了case type(Tree()):分,得到了TypeError: type() accepts 0 positional sub-patterns (1 given)分.这里发生的事情是这样的:case type(...)再次指定了一个模式.它不会作为表达式进行计算.它说匹配值需要是类型type(即是一个类),并且必须在括号中有属性.例如,

match Tree:
    case type(__init__=initializer):
        print("Tree is a type, and this is its initializer:")
        print(initializer)

这将匹配,并打印类似于

# => Tree is a type, and this is its initializer:
#    <function Tree.__init__ at 0x1098593a0>

同样的casenot匹配类型Tree的对象,只匹配类型本身!

但是,在本例中只能使用关键字参数.位置参数只有在定义为__match_args__的情况下才可用,如文档所述.类型type没有定义__match_args__,并且因为它是一个不可变的内置类型,所以case type(subpattern, ...)(子模式!not子表达式!)与case type(attribute=subpattern, ...)不同,它总是会产生错误.

Python相关问答推荐

TARete错误:类型对象任务没有属性模型'

如何使用symy打印方程?

重新匹配{ }中包含的文本,其中文本可能包含{{var}

所有列的滚动标准差,忽略NaN

使用Python更新字典中的值

pandas:排序多级列

在Django admin中自动完成相关字段筛选

改进大型数据集的框架性能

python中的解释会在后台调用函数吗?

将scipy. sparse矩阵直接保存为常规txt文件

在单次扫描中创建列表

Python—为什么我的代码返回一个TypeError

处理Gekko的非最优解

使用SeleniumBase保存和加载Cookie时出现问题

高效生成累积式三角矩阵

如何在Python中解析特定的文本,这些文本包含了同一行中的所有内容,

Django更新视图未更新

查找数据帧的给定列中是否存在特定值

无法使用请求模块从网页上抓取一些产品的名称

将鼠标悬停在海运`pairplot`的批注/高亮显示上